[SHLWAPI_WINETEST] Add a PCH.
[reactos.git] / modules / rostests / winetests / shlwapi / string.c
1 /* Unit test suite for SHLWAPI string functions
2 *
3 * Copyright 2003 Jon Griffiths
4 *
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.
9 *
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.
14 *
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
18 */
19
20 #include "precomp.h"
21
22 #define expect_eq(expr, val, type, fmt) do { \
23 type ret = expr; \
24 ok(ret == val, "Unexpected value of '" #expr "': " #fmt " instead of " #val "\n", ret); \
25 } while (0);
26
27 #define expect_eq2(expr, val1, val2, type, fmt) do { \
28 type ret = expr; \
29 ok(ret == val1 || ret == val2, "Unexpected value of '" #expr "': " #fmt " instead of " #val1 " or " #val2 "\n", ret); \
30 } while (0);
31
32 static BOOL (WINAPI *pChrCmpIA)(CHAR, CHAR);
33 static BOOL (WINAPI *pChrCmpIW)(WCHAR, WCHAR);
34 static BOOL (WINAPI *pIntlStrEqWorkerA)(BOOL,LPCSTR,LPCSTR,int);
35 static BOOL (WINAPI *pIntlStrEqWorkerW)(BOOL,LPCWSTR,LPCWSTR,int);
36 static DWORD (WINAPI *pSHAnsiToAnsi)(LPCSTR,LPSTR,int);
37 static DWORD (WINAPI *pSHUnicodeToUnicode)(LPCWSTR,LPWSTR,int);
38 static LPSTR (WINAPI *pStrCatBuffA)(LPSTR,LPCSTR,INT);
39 static LPWSTR (WINAPI *pStrCatBuffW)(LPWSTR,LPCWSTR,INT);
40 static DWORD (WINAPI *pStrCatChainW)(LPWSTR,DWORD,DWORD,LPCWSTR);
41 static LPSTR (WINAPI *pStrCpyNXA)(LPSTR,LPCSTR,int);
42 static LPWSTR (WINAPI *pStrCpyNXW)(LPWSTR,LPCWSTR,int);
43 static LPSTR (WINAPI *pStrFormatByteSize64A)(LONGLONG,LPSTR,UINT);
44 static LPSTR (WINAPI *pStrFormatKBSizeA)(LONGLONG,LPSTR,UINT);
45 static LPWSTR (WINAPI *pStrFormatKBSizeW)(LONGLONG,LPWSTR,UINT);
46 static BOOL (WINAPI *pStrIsIntlEqualA)(BOOL,LPCSTR,LPCSTR,int);
47 static BOOL (WINAPI *pStrIsIntlEqualW)(BOOL,LPCWSTR,LPCWSTR,int);
48 static LPWSTR (WINAPI *pStrPBrkW)(LPCWSTR,LPCWSTR);
49 static LPSTR (WINAPI *pStrRChrA)(LPCSTR,LPCSTR,WORD);
50 static HRESULT (WINAPI *pStrRetToBSTR)(STRRET*,LPCITEMIDLIST,BSTR*);
51 static HRESULT (WINAPI *pStrRetToBufA)(STRRET*,LPCITEMIDLIST,LPSTR,UINT);
52 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
53 static LPWSTR (WINAPI *pStrStrNW)(LPCWSTR,LPCWSTR,UINT);
54 static LPWSTR (WINAPI *pStrStrNIW)(LPCWSTR,LPCWSTR,UINT);
55 static INT (WINAPIV *pwnsprintfA)(LPSTR,INT,LPCSTR, ...);
56 static INT (WINAPIV *pwnsprintfW)(LPWSTR,INT,LPCWSTR, ...);
57 static LPWSTR (WINAPI *pStrChrNW)(LPCWSTR,WCHAR,UINT);
58 static BOOL (WINAPI *pStrToInt64ExA)(LPCSTR,DWORD,LONGLONG*);
59 static BOOL (WINAPI *pStrToInt64ExW)(LPCWSTR,DWORD,LONGLONG*);
60
61 static int strcmpW(const WCHAR *str1, const WCHAR *str2)
62 {
63 while (*str1 && (*str1 == *str2)) { str1++; str2++; }
64 return *str1 - *str2;
65 }
66
67 /* StrToInt/StrToIntEx results */
68 typedef struct tagStrToIntResult
69 {
70 const char* string;
71 int str_to_int;
72 LONGLONG str_to_int64_ex;
73 LONGLONG str_to_int64_hex;
74 } StrToIntResult;
75
76 static const StrToIntResult StrToInt_results[] = {
77 { "1099", 1099, 1099, 1099 },
78 { "4294967319", 23, ((LONGLONG)1 << 32) | 23, ((LONGLONG)1 << 32) | 23 },
79 { "+88987", 0, 88987, 88987 },
80 { "012", 12, 12, 12 },
81 { "-55", -55, -55, -55 },
82 { "-0", 0, 0, 0 },
83 { "0x44ff", 0, 0, 0x44ff },
84 { "0x2bdc546291f4b1", 0, 0, ((LONGLONG)0x2bdc54 << 32) | 0x6291f4b1 },
85 { "+0x44f4", 0, 0, 0x44f4 },
86 { "-0x44fd", 0, 0, 0x44fd },
87 { "+ 88987", 0, 0, 0 },
88 { "- 55", 0, 0, 0 },
89 { "- 0", 0, 0, 0 },
90 { "+ 0x44f4", 0, 0, 0 },
91 { "--0x44fd", 0, 0, 0 },
92 { " 1999", 0, 1999, 1999 },
93 { " +88987", 0, 88987, 88987 },
94 { " 012", 0, 12, 12 },
95 { " -55", 0, -55, -55 },
96 { " 0x44ff", 0, 0, 0x44ff },
97 { " +0x44f4", 0, 0, 0x44f4 },
98 { " -0x44fd", 0, 0, 0x44fd },
99 { NULL, 0, 0, 0 }
100 };
101
102 /* pStrFormatByteSize64/StrFormatKBSize results */
103 typedef struct tagStrFormatSizeResult
104 {
105 LONGLONG value;
106 const char* byte_size_64;
107 const char* kb_size;
108 int kb_size_broken;
109 const char* kb_size2;
110 } StrFormatSizeResult;
111
112
113 static const StrFormatSizeResult StrFormatSize_results[] = {
114 { -1023, "-1023 bytes", "0 KB"},
115 { -24, "-24 bytes", "0 KB"},
116 { 309, "309 bytes", "1 KB"},
117 { 10191, "9.95 KB", "10 KB"},
118 { 100353, "98.0 KB", "99 KB"},
119 { 1022286, "998 KB", "999 KB"},
120 { 1046862, "0.99 MB", "1,023 KB", 1, "1023 KB"},
121 { 1048574619, "999 MB", "1,023,999 KB", 1, "1023999 KB"},
122 { 1073741775, "0.99 GB", "1,048,576 KB", 1, "1048576 KB"},
123 { ((LONGLONG)0x000000f9 << 32) | 0xfffff94e, "999 GB", "1,048,575,999 KB", 1, "1048575999 KB"},
124 { ((LONGLONG)0x000000ff << 32) | 0xfffffa9b, "0.99 TB", "1,073,741,823 KB", 1, "1073741823 KB"},
125 { ((LONGLONG)0x0003e7ff << 32) | 0xfffffa9b, "999 TB", "1,073,741,823,999 KB", 1, "4294967295 KB"},
126 { ((LONGLONG)0x0003ffff << 32) | 0xfffffbe8, "0.99 PB", "1,099,511,627,775 KB", 1, "4294967295 KB"},
127 { ((LONGLONG)0x0f9fffff << 32) | 0xfffffd35, "999 PB", "1,099,511,627,776,000 KB", 1, "0 KB"},
128 { ((LONGLONG)0x0fffffff << 32) | 0xfffffa9b, "0.99 EB", "1,125,899,906,842,623 KB", 1, "4294967295 KB"},
129 { 0, NULL, NULL }
130 };
131
132 /* StrFromTimeIntervalA/StrFromTimeIntervalW results */
133 typedef struct tagStrFromTimeIntervalResult
134 {
135 DWORD ms;
136 int digits;
137 const char* time_interval;
138 } StrFromTimeIntervalResult;
139
140
141 static const StrFromTimeIntervalResult StrFromTimeInterval_results[] = {
142 { 1, 1, " 0 sec" },
143 { 1, 2, " 0 sec" },
144 { 1, 3, " 0 sec" },
145 { 1, 4, " 0 sec" },
146 { 1, 5, " 0 sec" },
147 { 1, 6, " 0 sec" },
148 { 1, 7, " 0 sec" },
149
150 { 1000000, 1, " 10 min" },
151 { 1000000, 2, " 16 min" },
152 { 1000000, 3, " 16 min 40 sec" },
153 { 1000000, 4, " 16 min 40 sec" },
154 { 1000000, 5, " 16 min 40 sec" },
155 { 1000000, 6, " 16 min 40 sec" },
156 { 1000000, 7, " 16 min 40 sec" },
157
158 { 1999999, 1, " 30 min" },
159 { 1999999, 2, " 33 min" },
160 { 1999999, 3, " 33 min 20 sec" },
161 { 1999999, 4, " 33 min 20 sec" },
162 { 1999999, 5, " 33 min 20 sec" },
163 { 1999999, 6, " 33 min 20 sec" },
164 { 1999999, 7, " 33 min 20 sec" },
165
166 { 3999997, 1, " 1 hr" },
167 { 3999997, 2, " 1 hr 6 min" },
168 { 3999997, 3, " 1 hr 6 min 40 sec" },
169 { 3999997, 4, " 1 hr 6 min 40 sec" },
170 { 3999997, 5, " 1 hr 6 min 40 sec" },
171 { 3999997, 6, " 1 hr 6 min 40 sec" },
172 { 3999997, 7, " 1 hr 6 min 40 sec" },
173
174 { 149999851, 7, " 41 hr 40 min 0 sec" },
175 { 150999850, 1, " 40 hr" },
176 { 150999850, 2, " 41 hr" },
177 { 150999850, 3, " 41 hr 50 min" },
178 { 150999850, 4, " 41 hr 56 min" },
179 { 150999850, 5, " 41 hr 56 min 40 sec" },
180 { 150999850, 6, " 41 hr 56 min 40 sec" },
181 { 150999850, 7, " 41 hr 56 min 40 sec" },
182
183 { 493999507, 1, " 100 hr" },
184 { 493999507, 2, " 130 hr" },
185 { 493999507, 3, " 137 hr" },
186 { 493999507, 4, " 137 hr 10 min" },
187 { 493999507, 5, " 137 hr 13 min" },
188 { 493999507, 6, " 137 hr 13 min 20 sec" },
189 { 493999507, 7, " 137 hr 13 min 20 sec" },
190
191 { 0, 0, NULL }
192 };
193
194
195 /* Returns true if the user interface is in English. Note that this does not
196 * presume of the formatting of dates, numbers, etc.
197 */
198 static BOOL is_lang_english(void)
199 {
200 static HMODULE hkernel32 = NULL;
201 static LANGID (WINAPI *pGetThreadUILanguage)(void) = NULL;
202 static LANGID (WINAPI *pGetUserDefaultUILanguage)(void) = NULL;
203
204 if (!hkernel32)
205 {
206 hkernel32 = GetModuleHandleA("kernel32.dll");
207 pGetThreadUILanguage = (void*)GetProcAddress(hkernel32, "GetThreadUILanguage");
208 pGetUserDefaultUILanguage = (void*)GetProcAddress(hkernel32, "GetUserDefaultUILanguage");
209 }
210 if (pGetThreadUILanguage)
211 return PRIMARYLANGID(pGetThreadUILanguage()) == LANG_ENGLISH;
212 if (pGetUserDefaultUILanguage)
213 return PRIMARYLANGID(pGetUserDefaultUILanguage()) == LANG_ENGLISH;
214
215 return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH;
216 }
217
218 /* Returns true if the dates, numbers, etc. are formatted using English
219 * conventions.
220 */
221 static BOOL is_locale_english(void)
222 {
223 /* Surprisingly GetThreadLocale() is irrelevant here */
224 return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH;
225 }
226
227 static void test_StrChrA(void)
228 {
229 char string[129];
230 WORD count;
231
232 /* this test crashes on win2k SP4 */
233 /*ok(!StrChrA(NULL,'\0'), "found a character in a NULL string!\n");*/
234
235 for (count = 32; count < 128; count++)
236 string[count] = (char)count;
237 string[128] = '\0';
238
239 for (count = 32; count < 128; count++)
240 {
241 LPSTR result = StrChrA(string+32, count);
242 INT pos = result - string;
243 ok(pos == count, "found char '%c' in wrong place: got %d, expected %d\n", count, pos, count);
244 }
245
246 for (count = 32; count < 128; count++)
247 {
248 LPSTR result = StrChrA(string+count+1, count);
249 ok(!result, "found char '%c' not in the string\n", count);
250 }
251 }
252
253 static void test_StrChrW(void)
254 {
255 WCHAR string[16385];
256 WORD count;
257
258 /* this test crashes on win2k SP4 */
259 /*ok(!StrChrW(NULL,'\0'), "found a character in a NULL string!\n");*/
260
261 for (count = 32; count < 16384; count++)
262 string[count] = count;
263 string[16384] = '\0';
264
265 for (count = 32; count < 16384; count++)
266 {
267 LPWSTR result = StrChrW(string+32, count);
268 ok((result - string) == count, "found char %d in wrong place\n", count);
269 }
270
271 for (count = 32; count < 16384; count++)
272 {
273 LPWSTR result = StrChrW(string+count+1, count);
274 ok(!result, "found char not in the string\n");
275 }
276 }
277
278 static void test_StrChrIA(void)
279 {
280 char string[129];
281 WORD count;
282
283 /* this test crashes on win2k SP4 */
284 /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/
285
286 for (count = 32; count < 128; count++)
287 string[count] = (char)count;
288 string[128] = '\0';
289
290 for (count = 'A'; count <= 'X'; count++)
291 {
292 LPSTR result = StrChrIA(string+32, count);
293
294 ok(result - string == count, "found char '%c' in wrong place\n", count);
295 ok(StrChrIA(result, count)!=NULL, "didn't find lowercase '%c'\n", count);
296 }
297
298 for (count = 'a'; count < 'z'; count++)
299 {
300 LPSTR result = StrChrIA(string+count+1, count);
301 ok(!result, "found char not in the string\n");
302 }
303 }
304
305 static void test_StrChrIW(void)
306 {
307 WCHAR string[129];
308 WORD count;
309
310 /* this test crashes on win2k SP4 */
311 /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/
312
313 for (count = 32; count < 128; count++)
314 string[count] = count;
315 string[128] = '\0';
316
317 for (count = 'A'; count <= 'X'; count++)
318 {
319 LPWSTR result = StrChrIW(string+32, count);
320
321 ok(result - string == count, "found char '%c' in wrong place\n", count);
322 ok(StrChrIW(result, count)!=NULL, "didn't find lowercase '%c'\n", count);
323 }
324
325 for (count = 'a'; count < 'z'; count++)
326 {
327 LPWSTR result = StrChrIW(string+count+1, count);
328 ok(!result, "found char not in the string\n");
329 }
330 }
331
332 static void test_StrRChrA(void)
333 {
334 char string[129];
335 WORD count;
336
337 /* this test crashes on win2k SP4 */
338 /*ok(!StrRChrA(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/
339
340 for (count = 32; count < 128; count++)
341 string[count] = (char)count;
342 string[128] = '\0';
343
344 for (count = 32; count < 128; count++)
345 {
346 LPSTR result = StrRChrA(string+32, NULL, count);
347 ok(result - string == count, "found char %d in wrong place\n", count);
348 }
349
350 for (count = 32; count < 128; count++)
351 {
352 LPSTR result = StrRChrA(string+count+1, NULL, count);
353 ok(!result, "found char not in the string\n");
354 }
355
356 for (count = 32; count < 128; count++)
357 {
358 LPSTR result = StrRChrA(string+count+1, string + 127, count);
359 ok(!result, "found char not in the string\n");
360 }
361 }
362
363 static void test_StrRChrW(void)
364 {
365 WCHAR string[129];
366 WORD count;
367
368 /* this test crashes on win2k SP4 */
369 /*ok(!StrRChrW(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/
370
371 for (count = 32; count < 128; count++)
372 string[count] = count;
373 string[128] = '\0';
374
375 for (count = 32; count < 128; count++)
376 {
377 LPWSTR result = StrRChrW(string+32, NULL, count);
378 INT pos = result - string;
379 ok(pos == count, "found char %d in wrong place: got %d, expected %d\n", count, pos, count);
380 }
381
382 for (count = 32; count < 128; count++)
383 {
384 LPWSTR result = StrRChrW(string+count+1, NULL, count);
385 ok(!result, "found char %d not in the string\n", count);
386 }
387
388 for (count = 32; count < 128; count++)
389 {
390 LPWSTR result = StrRChrW(string+count+1, string + 127, count);
391 ok(!result, "found char %d not in the string\n", count);
392 }
393 }
394
395 static void test_StrCpyW(void)
396 {
397 WCHAR szSrc[256];
398 WCHAR szBuff[256];
399 const StrFormatSizeResult* result = StrFormatSize_results;
400 LPWSTR lpRes;
401
402 while(result->value)
403 {
404 MultiByteToWideChar(CP_ACP,0,result->byte_size_64,-1,szSrc,sizeof(szSrc)/sizeof(WCHAR));
405
406 lpRes = StrCpyW(szBuff, szSrc);
407 ok(!StrCmpW(szSrc, szBuff) && lpRes == szBuff, "Copied string %s wrong\n", result->byte_size_64);
408 result++;
409 }
410
411 /* this test crashes on win2k SP4 */
412 /*lpRes = StrCpyW(szBuff, NULL);*/
413 /*ok(lpRes == szBuff, "Wrong return value: got %p expected %p\n", lpRes, szBuff);*/
414
415 /* this test crashes on win2k SP4 */
416 /*lpRes = StrCpyW(NULL, szSrc);*/
417 /*ok(lpRes == NULL, "Wrong return value: got %p expected NULL\n", lpRes);*/
418
419 /* this test crashes on win2k SP4 */
420 /*lpRes = StrCpyW(NULL, NULL);*/
421 /*ok(lpRes == NULL, "Wrong return value: got %p expected NULL\n", lpRes);*/
422 }
423
424 static void test_StrChrNW(void)
425 {
426 static const WCHAR string[] = {'T','e','s','t','i','n','g',' ','S','t','r','i','n','g',0};
427 LPWSTR p;
428
429 if (!pStrChrNW)
430 {
431 win_skip("StrChrNW not available\n");
432 return;
433 }
434
435 p = pStrChrNW(string,'t',10);
436 ok(*p=='t',"Found wrong 't'\n");
437 ok(*(p+1)=='i',"next should be 'i'\n");
438
439 p = pStrChrNW(string,'S',10);
440 ok(*p=='S',"Found wrong 'S'\n");
441
442 p = pStrChrNW(string,'r',10);
443 ok(p==NULL,"Should not have found 'r'\n");
444 }
445
446 static void test_StrToIntA(void)
447 {
448 const StrToIntResult *result = StrToInt_results;
449 int return_val;
450
451 while (result->string)
452 {
453 return_val = StrToIntA(result->string);
454 ok(return_val == result->str_to_int, "converted '%s' wrong (%d)\n",
455 result->string, return_val);
456 result++;
457 }
458 }
459
460 static void test_StrToIntW(void)
461 {
462 WCHAR szBuff[256];
463 const StrToIntResult *result = StrToInt_results;
464 int return_val;
465
466 while (result->string)
467 {
468 MultiByteToWideChar(CP_ACP,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
469 return_val = StrToIntW(szBuff);
470 ok(return_val == result->str_to_int, "converted '%s' wrong (%d)\n",
471 result->string, return_val);
472 result++;
473 }
474 }
475
476 static void test_StrToIntExA(void)
477 {
478 const StrToIntResult *result = StrToInt_results;
479 int return_val;
480 BOOL bRet;
481
482 while (result->string)
483 {
484 return_val = -1;
485 bRet = StrToIntExA(result->string,0,&return_val);
486 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
487 result->string);
488 if (bRet)
489 ok(return_val == (int)result->str_to_int64_ex, "converted '%s' wrong (%d)\n",
490 result->string, return_val);
491 result++;
492 }
493
494 result = StrToInt_results;
495 while (result->string)
496 {
497 return_val = -1;
498 bRet = StrToIntExA(result->string,STIF_SUPPORT_HEX,&return_val);
499 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
500 result->string);
501 if (bRet)
502 ok(return_val == (int)result->str_to_int64_hex, "converted '%s' wrong (%d)\n",
503 result->string, return_val);
504 result++;
505 }
506 }
507
508 static void test_StrToIntExW(void)
509 {
510 WCHAR szBuff[256];
511 const StrToIntResult *result = StrToInt_results;
512 int return_val;
513 BOOL bRet;
514
515 while (result->string)
516 {
517 return_val = -1;
518 MultiByteToWideChar(CP_ACP,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
519 bRet = StrToIntExW(szBuff, 0, &return_val);
520 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
521 result->string);
522 if (bRet)
523 ok(return_val == (int)result->str_to_int64_ex, "converted '%s' wrong (%d)\n",
524 result->string, return_val);
525 result++;
526 }
527
528 result = StrToInt_results;
529 while (result->string)
530 {
531 return_val = -1;
532 MultiByteToWideChar(CP_ACP,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
533 bRet = StrToIntExW(szBuff, STIF_SUPPORT_HEX, &return_val);
534 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
535 result->string);
536 if (bRet)
537 ok(return_val == (int)result->str_to_int64_hex, "converted '%s' wrong (%d)\n",
538 result->string, return_val);
539 result++;
540 }
541 }
542
543 static void test_StrToInt64ExA(void)
544 {
545 const StrToIntResult *result = StrToInt_results;
546 LONGLONG return_val;
547 BOOL bRet;
548
549 if (!pStrToInt64ExA)
550 {
551 win_skip("StrToInt64ExA() is not available\n");
552 return;
553 }
554
555 while (result->string)
556 {
557 return_val = -1;
558 bRet = pStrToInt64ExA(result->string,0,&return_val);
559 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
560 result->string);
561 if (bRet)
562 ok(return_val == result->str_to_int64_ex, "converted '%s' wrong (%s)\n",
563 result->string, wine_dbgstr_longlong(return_val));
564 result++;
565 }
566
567 result = StrToInt_results;
568 while (result->string)
569 {
570 return_val = -1;
571 bRet = pStrToInt64ExA(result->string,STIF_SUPPORT_HEX,&return_val);
572 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
573 result->string);
574 if (bRet)
575 ok(return_val == result->str_to_int64_hex, "converted '%s' wrong (%s)\n",
576 result->string, wine_dbgstr_longlong(return_val));
577 result++;
578 }
579 }
580
581 static void test_StrToInt64ExW(void)
582 {
583 WCHAR szBuff[256];
584 const StrToIntResult *result = StrToInt_results;
585 LONGLONG return_val;
586 BOOL bRet;
587
588 if (!pStrToInt64ExW)
589 {
590 win_skip("StrToInt64ExW() is not available\n");
591 return;
592 }
593
594 while (result->string)
595 {
596 return_val = -1;
597 MultiByteToWideChar(CP_ACP,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
598 bRet = pStrToInt64ExW(szBuff, 0, &return_val);
599 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
600 result->string);
601 if (bRet)
602 ok(return_val == result->str_to_int64_ex, "converted '%s' wrong (%s)\n",
603 result->string, wine_dbgstr_longlong(return_val));
604 result++;
605 }
606
607 result = StrToInt_results;
608 while (result->string)
609 {
610 return_val = -1;
611 MultiByteToWideChar(CP_ACP,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
612 bRet = pStrToInt64ExW(szBuff, STIF_SUPPORT_HEX, &return_val);
613 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
614 result->string);
615 if (bRet)
616 ok(return_val == result->str_to_int64_hex, "converted '%s' wrong (%s)\n",
617 result->string, wine_dbgstr_longlong(return_val));
618 result++;
619 }
620 }
621
622 static void test_StrDupA(void)
623 {
624 LPSTR lpszStr;
625 const StrFormatSizeResult* result = StrFormatSize_results;
626
627 while(result->value)
628 {
629 lpszStr = StrDupA(result->byte_size_64);
630
631 ok(lpszStr != NULL, "Dup failed\n");
632 if (lpszStr)
633 {
634 ok(!strcmp(result->byte_size_64, lpszStr), "Copied string wrong\n");
635 LocalFree(lpszStr);
636 }
637 result++;
638 }
639
640 /* Later versions of shlwapi return NULL for this, but earlier versions
641 * returned an empty string (as Wine does).
642 */
643 lpszStr = StrDupA(NULL);
644 ok(lpszStr == NULL || *lpszStr == '\0', "NULL string returned %p\n", lpszStr);
645 LocalFree(lpszStr);
646 }
647
648 static void test_StrFormatByteSize64A(void)
649 {
650 char szBuff[256];
651 const StrFormatSizeResult* result = StrFormatSize_results;
652
653 if (!pStrFormatByteSize64A)
654 {
655 win_skip("StrFormatByteSize64A() is not available\n");
656 return;
657 }
658
659 while(result->value)
660 {
661 pStrFormatByteSize64A(result->value, szBuff, 256);
662
663 ok(!strcmp(result->byte_size_64, szBuff),
664 "Formatted %s wrong: got %s, expected %s\n",
665 wine_dbgstr_longlong(result->value), szBuff, result->byte_size_64);
666
667 result++;
668 }
669 }
670
671 static void test_StrFormatKBSizeW(void)
672 {
673 WCHAR szBuffW[256];
674 char szBuff[256];
675 const StrFormatSizeResult* result = StrFormatSize_results;
676
677 if (!pStrFormatKBSizeW)
678 {
679 win_skip("StrFormatKBSizeW() is not available\n");
680 return;
681 }
682
683 while(result->value)
684 {
685 pStrFormatKBSizeW(result->value, szBuffW, 256);
686 WideCharToMultiByte(CP_ACP,0,szBuffW,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR),NULL,NULL);
687
688 ok(!strcmp(result->kb_size, szBuff), "Formatted %s wrong: got %s, expected %s\n",
689 wine_dbgstr_longlong(result->value), szBuff, result->kb_size);
690 result++;
691 }
692 }
693
694 static void test_StrFormatKBSizeA(void)
695 {
696 char szBuff[256];
697 const StrFormatSizeResult* result = StrFormatSize_results;
698
699 if (!pStrFormatKBSizeA)
700 {
701 win_skip("StrFormatKBSizeA() is not available\n");
702 return;
703 }
704
705 while(result->value)
706 {
707 pStrFormatKBSizeA(result->value, szBuff, 256);
708
709 /* shlwapi on Win98 SE does not appear to apply delimiters to the output
710 * and does not correctly handle extremely large values. */
711 ok(!strcmp(result->kb_size, szBuff) ||
712 (result->kb_size_broken && !strcmp(result->kb_size2, szBuff)),
713 "Formatted %s wrong: got %s, expected %s\n",
714 wine_dbgstr_longlong(result->value), szBuff, result->kb_size);
715 result++;
716 }
717 }
718
719 static void test_StrFromTimeIntervalA(void)
720 {
721 char szBuff[256];
722 const StrFromTimeIntervalResult* result = StrFromTimeInterval_results;
723
724 while(result->ms)
725 {
726 StrFromTimeIntervalA(szBuff, 256, result->ms, result->digits);
727
728 ok(!strcmp(result->time_interval, szBuff), "Formatted %d %d wrong: %s\n",
729 result->ms, result->digits, szBuff);
730 result++;
731 }
732 }
733
734 static void test_StrCmpA(void)
735 {
736 static const char str1[] = {'a','b','c','d','e','f'};
737 static const char str2[] = {'a','B','c','d','e','f'};
738 ok(0 != StrCmpNA(str1, str2, 6), "StrCmpNA is case-insensitive\n");
739 ok(0 == StrCmpNIA(str1, str2, 6), "StrCmpNIA is case-sensitive\n");
740 if (pChrCmpIA) {
741 ok(!pChrCmpIA('a', 'a'), "ChrCmpIA doesn't work at all!\n");
742 ok(!pChrCmpIA('b', 'B'), "ChrCmpIA is not case-insensitive\n");
743 ok(pChrCmpIA('a', 'z'), "ChrCmpIA believes that a == z!\n");
744 }
745 else
746 win_skip("ChrCmpIA() is not available\n");
747
748 if (pStrIsIntlEqualA)
749 {
750 ok(pStrIsIntlEqualA(FALSE, str1, str2, 5), "StrIsIntlEqualA(FALSE,...) isn't case-insensitive\n");
751 ok(!pStrIsIntlEqualA(TRUE, str1, str2, 5), "StrIsIntlEqualA(TRUE,...) isn't case-sensitive\n");
752 }
753 else
754 win_skip("StrIsIntlEqualA() is not available\n");
755
756 if (pIntlStrEqWorkerA)
757 {
758 ok(pIntlStrEqWorkerA(FALSE, str1, str2, 5), "IntlStrEqWorkerA(FALSE,...) isn't case-insensitive\n");
759 ok(!pIntlStrEqWorkerA(TRUE, str1, str2, 5), "pIntlStrEqWorkerA(TRUE,...) isn't case-sensitive\n");
760 }
761 else
762 win_skip("IntlStrEqWorkerA() is not available\n");
763 }
764
765 static void test_StrCmpW(void)
766 {
767 static const WCHAR str1[] = {'a','b','c','d','e','f'};
768 static const WCHAR str2[] = {'a','B','c','d','e','f'};
769 ok(0 != StrCmpNW(str1, str2, 5), "StrCmpNW is case-insensitive\n");
770 ok(0 == StrCmpNIW(str1, str2, 5), "StrCmpNIW is case-sensitive\n");
771 if (pChrCmpIW) {
772 ok(!pChrCmpIW('a', 'a'), "ChrCmpIW doesn't work at all!\n");
773 ok(!pChrCmpIW('b', 'B'), "ChrCmpIW is not case-insensitive\n");
774 ok(pChrCmpIW('a', 'z'), "ChrCmpIW believes that a == z!\n");
775 }
776 else
777 win_skip("ChrCmpIW() is not available\n");
778
779 if (pStrIsIntlEqualW)
780 {
781 ok(pStrIsIntlEqualW(FALSE, str1, str2, 5), "StrIsIntlEqualW(FALSE,...) isn't case-insensitive\n");
782 ok(!pStrIsIntlEqualW(TRUE, str1, str2, 5), "StrIsIntlEqualW(TRUE,...) isn't case-sensitive\n");
783 }
784 else
785 win_skip("StrIsIntlEqualW() is not available\n");
786
787 if (pIntlStrEqWorkerW)
788 {
789 ok(pIntlStrEqWorkerW(FALSE, str1, str2, 5), "IntlStrEqWorkerW(FALSE,...) isn't case-insensitive\n");
790 ok(!pIntlStrEqWorkerW(TRUE, str1, str2, 5), "IntlStrEqWorkerW(TRUE,...) isn't case-sensitive\n");
791 }
792 else
793 win_skip("IntlStrEqWorkerW() is not available\n");
794 }
795
796 static WCHAR *CoDupStrW(const char* src)
797 {
798 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
799 WCHAR* szTemp = CoTaskMemAlloc(len * sizeof(WCHAR));
800 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
801 return szTemp;
802 }
803
804 static void test_StrRetToBSTR(void)
805 {
806 static const WCHAR szTestW[] = { 'T','e','s','t','\0' };
807 ITEMIDLIST iidl[10];
808 BSTR bstr;
809 STRRET strret;
810 HRESULT ret;
811
812 if (!pStrRetToBSTR)
813 {
814 win_skip("StrRetToBSTR() is not available\n");
815 return;
816 }
817
818 strret.uType = STRRET_WSTR;
819 U(strret).pOleStr = CoDupStrW("Test");
820 bstr = 0;
821 ret = pStrRetToBSTR(&strret, NULL, &bstr);
822 ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
823 "STRRET_WSTR: dup failed, ret=0x%08x, bstr %p\n", ret, bstr);
824 SysFreeString(bstr);
825
826 strret.uType = STRRET_CSTR;
827 lstrcpyA(U(strret).cStr, "Test");
828 ret = pStrRetToBSTR(&strret, NULL, &bstr);
829 ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
830 "STRRET_CSTR: dup failed, ret=0x%08x, bstr %p\n", ret, bstr);
831 SysFreeString(bstr);
832
833 strret.uType = STRRET_OFFSET;
834 U(strret).uOffset = 1;
835 strcpy((char*)&iidl, " Test");
836 ret = pStrRetToBSTR(&strret, iidl, &bstr);
837 ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
838 "STRRET_OFFSET: dup failed, ret=0x%08x, bstr %p\n", ret, bstr);
839 SysFreeString(bstr);
840
841 /* Native crashes if str is NULL */
842 }
843
844 static void test_StrCpyNXA(void)
845 {
846 LPCSTR lpSrc = "hello";
847 LPSTR lpszRes;
848 char dest[8];
849
850 if (!pStrCpyNXA)
851 {
852 win_skip("StrCpyNXA() is not available\n");
853 return;
854 }
855
856 memset(dest, '\n', sizeof(dest));
857 lpszRes = pStrCpyNXA(dest, lpSrc, sizeof(dest)/sizeof(dest[0]));
858 ok(lpszRes == dest + 5 && !memcmp(dest, "hello\0\n\n", sizeof(dest)),
859 "StrCpyNXA: expected %p, \"hello\\0\\n\\n\", got %p, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
860 dest + 5, lpszRes, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
861 }
862
863 static void test_StrCpyNXW(void)
864 {
865 static const WCHAR lpInit[] = { '\n','\n','\n','\n','\n','\n','\n','\n' };
866 static const WCHAR lpSrc[] = { 'h','e','l','l','o','\0' };
867 static const WCHAR lpRes[] = { 'h','e','l','l','o','\0','\n','\n' };
868 LPWSTR lpszRes;
869 WCHAR dest[8];
870
871 if (!pStrCpyNXW)
872 {
873 win_skip("StrCpyNXW() is not available\n");
874 return;
875 }
876
877 memcpy(dest, lpInit, sizeof(lpInit));
878 lpszRes = pStrCpyNXW(dest, lpSrc, sizeof(dest)/sizeof(dest[0]));
879 ok(lpszRes == dest + 5 && !memcmp(dest, lpRes, sizeof(dest)),
880 "StrCpyNXW: expected %p, \"hello\\0\\n\\n\", got %p, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
881 dest + 5, lpszRes, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
882 }
883
884 #define check_strrstri(type, str, pos, needle, exp) \
885 ret##type = StrRStrI##type(str, str+pos, needle); \
886 ok(ret##type == (exp), "Type " #type ", expected %p but got %p (string base %p)\n", \
887 (exp), ret##type, str);
888
889 static void test_StrRStrI(void)
890 {
891 static const CHAR szTest[] = "yAxxxxAy";
892 static const CHAR szTest2[] = "ABABABAB";
893 static const WCHAR wszTest[] = {'y','A','x','x','x','x','A','y',0};
894 static const WCHAR wszTest2[] = {'A','B','A','B','A','B','A','B',0};
895
896 static const WCHAR wszPattern1[] = {'A',0};
897 static const WCHAR wszPattern2[] = {'a','X',0};
898 static const WCHAR wszPattern3[] = {'A','y',0};
899 static const WCHAR wszPattern4[] = {'a','b',0};
900 LPWSTR retW;
901 LPSTR retA;
902
903 check_strrstri(A, szTest, 4, "A", szTest+1);
904 check_strrstri(A, szTest, 4, "aX", szTest+1);
905 check_strrstri(A, szTest, 4, "Ay", NULL);
906 check_strrstri(W, wszTest, 4, wszPattern1, wszTest+1);
907 check_strrstri(W, wszTest, 4, wszPattern2, wszTest+1);
908 check_strrstri(W, wszTest, 4, wszPattern3, NULL);
909
910 check_strrstri(A, szTest2, 4, "ab", szTest2+2);
911 check_strrstri(A, szTest2, 3, "ab", szTest2+2);
912 check_strrstri(A, szTest2, 2, "ab", szTest2);
913 check_strrstri(A, szTest2, 1, "ab", szTest2);
914 check_strrstri(A, szTest2, 0, "ab", NULL);
915 check_strrstri(W, wszTest2, 4, wszPattern4, wszTest2+2);
916 check_strrstri(W, wszTest2, 3, wszPattern4, wszTest2+2);
917 check_strrstri(W, wszTest2, 2, wszPattern4, wszTest2);
918 check_strrstri(W, wszTest2, 1, wszPattern4, wszTest2);
919 check_strrstri(W, wszTest2, 0, wszPattern4, NULL);
920
921 }
922
923 static void test_SHAnsiToAnsi(void)
924 {
925 char dest[8];
926 DWORD dwRet;
927
928 if (!pSHAnsiToAnsi)
929 {
930 win_skip("SHAnsiToAnsi() is not available\n");
931 return;
932 }
933
934 if (pSHAnsiToAnsi == (void *)pStrPBrkW)
935 {
936 win_skip("Ordinal 345 corresponds to StrPBrkW, skipping SHAnsiToAnsi tests\n");
937 return;
938 }
939
940 memset(dest, '\n', sizeof(dest));
941 dwRet = pSHAnsiToAnsi("hello", dest, sizeof(dest)/sizeof(dest[0]));
942 ok(dwRet == 6 && !memcmp(dest, "hello\0\n\n", sizeof(dest)),
943 "SHAnsiToAnsi: expected 6, \"hello\\0\\n\\n\", got %d, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
944 dwRet, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
945 }
946
947 static void test_SHUnicodeToUnicode(void)
948 {
949 static const WCHAR lpInit[] = { '\n','\n','\n','\n','\n','\n','\n','\n' };
950 static const WCHAR lpSrc[] = { 'h','e','l','l','o','\0' };
951 static const WCHAR lpRes[] = { 'h','e','l','l','o','\0','\n','\n' };
952 WCHAR dest[8];
953 DWORD dwRet;
954
955 if (!pSHUnicodeToUnicode)
956 {
957 win_skip("SHUnicodeToUnicode() is not available\n");
958 return;
959 }
960
961 if (pSHUnicodeToUnicode == (void *)pStrRChrA)
962 {
963 win_skip("Ordinal 346 corresponds to StrRChrA, skipping SHUnicodeToUnicode tests\n");
964 return;
965 }
966
967 memcpy(dest, lpInit, sizeof(lpInit));
968 dwRet = pSHUnicodeToUnicode(lpSrc, dest, sizeof(dest)/sizeof(dest[0]));
969 ok(dwRet == 6 && !memcmp(dest, lpRes, sizeof(dest)),
970 "SHUnicodeToUnicode: expected 6, \"hello\\0\\n\\n\", got %d, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
971 dwRet, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
972 }
973
974 static void test_StrXXX_overflows(void)
975 {
976 CHAR str1[2*MAX_PATH+1], buf[2*MAX_PATH];
977 WCHAR wstr1[2*MAX_PATH+1], wbuf[2*MAX_PATH];
978 const WCHAR fmt[] = {'%','s',0};
979 STRRET strret;
980 HRESULT hres;
981 int ret;
982 int i;
983
984 for (i=0; i<2*MAX_PATH; i++)
985 {
986 str1[i] = '0'+(i%10);
987 wstr1[i] = '0'+(i%10);
988 }
989 str1[2*MAX_PATH] = 0;
990 wstr1[2*MAX_PATH] = 0;
991
992 memset(buf, 0xbf, sizeof(buf));
993 expect_eq(StrCpyNA(buf, str1, 10), buf, PCHAR, "%p");
994 expect_eq(buf[9], 0, CHAR, "%x");
995 expect_eq(buf[10], '\xbf', CHAR, "%x");
996
997 if (pStrCatBuffA)
998 {
999 expect_eq(pStrCatBuffA(buf, str1, 100), buf, PCHAR, "%p");
1000 expect_eq(buf[99], 0, CHAR, "%x");
1001 expect_eq(buf[100], '\xbf', CHAR, "%x");
1002 }
1003 else
1004 win_skip("StrCatBuffA() is not available\n");
1005
1006 if (0)
1007 {
1008 /* crashes on XP */
1009 StrCpyNW(wbuf, (LPCWSTR)0x1, 10);
1010 StrCpyNW((LPWSTR)0x1, wstr1, 10);
1011 }
1012
1013 memset(wbuf, 0xbf, sizeof(wbuf));
1014 expect_eq(StrCpyNW(wbuf, (LPCWSTR)0x1, 1), wbuf, PWCHAR, "%p");
1015 expect_eq(wbuf[0], 0, WCHAR, "%x");
1016 expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x");
1017
1018 memset(wbuf, 0xbf, sizeof(wbuf));
1019 expect_eq(StrCpyNW(wbuf, 0, 10), wbuf, PWCHAR, "%p");
1020 expect_eq(wbuf[0], 0, WCHAR, "%x");
1021 expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x");
1022
1023 memset(wbuf, 0xbf, sizeof(wbuf));
1024 expect_eq(StrCpyNW(wbuf, 0, 0), wbuf, PWCHAR, "%p");
1025 expect_eq(wbuf[0], (WCHAR)0xbfbf, WCHAR, "%x");
1026 expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x");
1027
1028 memset(wbuf, 0xbf, sizeof(wbuf));
1029 expect_eq(StrCpyNW(wbuf, wstr1, 0), wbuf, PWCHAR, "%p");
1030 expect_eq(wbuf[0], (WCHAR)0xbfbf, WCHAR, "%x");
1031 expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x");
1032
1033 memset(wbuf, 0xbf, sizeof(wbuf));
1034 expect_eq(StrCpyNW(wbuf, wstr1, 10), wbuf, PWCHAR, "%p");
1035 expect_eq(wbuf[9], 0, WCHAR, "%x");
1036 expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x");
1037
1038 if (pStrCatBuffW)
1039 {
1040 expect_eq(pStrCatBuffW(wbuf, wstr1, 100), wbuf, PWCHAR, "%p");
1041 expect_eq(wbuf[99], 0, WCHAR, "%x");
1042 expect_eq(wbuf[100], (WCHAR)0xbfbf, WCHAR, "%x");
1043 }
1044 else
1045 win_skip("StrCatBuffW() is not available\n");
1046
1047 if (pStrRetToBufW)
1048 {
1049 memset(wbuf, 0xbf, sizeof(wbuf));
1050 strret.uType = STRRET_WSTR;
1051 U(strret).pOleStr = StrDupW(wstr1);
1052 hres = pStrRetToBufW(&strret, NULL, wbuf, 10);
1053 ok(hres == E_NOT_SUFFICIENT_BUFFER || broken(hres == S_OK) /* winxp */,
1054 "StrRetToBufW returned %08x\n", hres);
1055 if (hres == E_NOT_SUFFICIENT_BUFFER)
1056 expect_eq(wbuf[0], 0, WCHAR, "%x");
1057 expect_eq(wbuf[9], 0, WCHAR, "%x");
1058 expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x");
1059
1060 memset(wbuf, 0xbf, sizeof(wbuf));
1061 strret.uType = STRRET_CSTR;
1062 StrCpyNA(U(strret).cStr, str1, MAX_PATH);
1063 hres = pStrRetToBufW(&strret, NULL, wbuf, 10);
1064 ok(hres == S_OK, "StrRetToBufW returned %08x\n", hres);
1065 ok(!memcmp(wbuf, wstr1, 9*sizeof(WCHAR)) && !wbuf[9], "StrRetToBuf returned %s\n", wine_dbgstr_w(wbuf));
1066
1067 memset(wbuf, 0xbf, sizeof(wbuf));
1068 strret.uType = STRRET_WSTR;
1069 U(strret).pOleStr = NULL;
1070 hres = pStrRetToBufW(&strret, NULL, wbuf, 10);
1071 ok(hres == E_FAIL, "StrRetToBufW returned %08x\n", hres);
1072 ok(!wbuf[0], "StrRetToBuf returned %s\n", wine_dbgstr_w(wbuf));
1073 }
1074 else
1075 win_skip("StrRetToBufW() is not available\n");
1076
1077 if (pStrRetToBufA)
1078 {
1079 memset(buf, 0xbf, sizeof(buf));
1080 strret.uType = STRRET_CSTR;
1081 StrCpyNA(U(strret).cStr, str1, MAX_PATH);
1082 expect_eq2(pStrRetToBufA(&strret, NULL, buf, 10), S_OK, E_NOT_SUFFICIENT_BUFFER /* Vista */, HRESULT, "%x");
1083 expect_eq(buf[9], 0, CHAR, "%x");
1084 expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x");
1085 }
1086 else
1087 win_skip("StrRetToBufA() is not available\n");
1088
1089 if (pwnsprintfA)
1090 {
1091 memset(buf, 0xbf, sizeof(buf));
1092 ret = pwnsprintfA(buf, 10, "%s", str1);
1093 ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wnsprintfA return %d, expected 9 or -1\n", ret);
1094 expect_eq(buf[9], 0, CHAR, "%x");
1095 expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x");
1096 }
1097 else
1098 win_skip("wnsprintfA() is not available\n");
1099
1100 if (pwnsprintfW)
1101 {
1102 memset(wbuf, 0xbf, sizeof(wbuf));
1103 ret = pwnsprintfW(wbuf, 10, fmt, wstr1);
1104 ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wnsprintfW return %d, expected 9 or -1\n", ret);
1105 expect_eq(wbuf[9], 0, WCHAR, "%x");
1106 expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x");
1107 }
1108 else
1109 win_skip("wnsprintfW() is not available\n");
1110 }
1111
1112 static void test_StrStrA(void)
1113 {
1114 static const char *deadbeefA = "DeAdBeEf";
1115
1116 const struct
1117 {
1118 const char *search;
1119 const char *expect;
1120 } StrStrA_cases[] =
1121 {
1122 {"", NULL},
1123 {"DeAd", deadbeefA},
1124 {"dead", NULL},
1125 {"AdBe", deadbeefA + 2},
1126 {"adbe", NULL},
1127 {"BeEf", deadbeefA + 4},
1128 {"beef", NULL},
1129 };
1130
1131 LPSTR ret;
1132 int i;
1133
1134 /* Tests crash on Win2k */
1135 if (0)
1136 {
1137 ret = StrStrA(NULL, NULL);
1138 ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret);
1139
1140 ret = StrStrA(NULL, "");
1141 ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret);
1142
1143 ret = StrStrA("", NULL);
1144 ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret);
1145 }
1146
1147 ret = StrStrA("", "");
1148 ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret);
1149
1150 for (i = 0; i < sizeof(StrStrA_cases)/sizeof(StrStrA_cases[0]); i++)
1151 {
1152 ret = StrStrA(deadbeefA, StrStrA_cases[i].search);
1153 ok(ret == StrStrA_cases[i].expect,
1154 "[%d] Expected StrStrA to return %p, got %p\n",
1155 i, StrStrA_cases[i].expect, ret);
1156 }
1157 }
1158
1159 static void test_StrStrW(void)
1160 {
1161 static const WCHAR emptyW[] = {0};
1162 static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
1163 static const WCHAR deadW[] = {'D','e','A','d',0};
1164 static const WCHAR dead_lowerW[] = {'d','e','a','d',0};
1165 static const WCHAR adbeW[] = {'A','d','B','e',0};
1166 static const WCHAR adbe_lowerW[] = {'a','d','b','e',0};
1167 static const WCHAR beefW[] = {'B','e','E','f',0};
1168 static const WCHAR beef_lowerW[] = {'b','e','e','f',0};
1169
1170 const struct
1171 {
1172 const WCHAR *search;
1173 const WCHAR *expect;
1174 } StrStrW_cases[] =
1175 {
1176 {emptyW, NULL},
1177 {deadW, deadbeefW},
1178 {dead_lowerW, NULL},
1179 {adbeW, deadbeefW + 2},
1180 {adbe_lowerW, NULL},
1181 {beefW, deadbeefW + 4},
1182 {beef_lowerW, NULL},
1183 };
1184
1185 LPWSTR ret;
1186 int i;
1187
1188 /* Tests crash on Win2k */
1189 if (0)
1190 {
1191 ret = StrStrW(NULL, NULL);
1192 ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret);
1193
1194 ret = StrStrW(NULL, emptyW);
1195 ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret);
1196
1197 ret = StrStrW(emptyW, NULL);
1198 ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret);
1199 }
1200
1201 ret = StrStrW(emptyW, emptyW);
1202 ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret);
1203
1204 for (i = 0; i < sizeof(StrStrW_cases)/sizeof(StrStrW_cases[0]); i++)
1205 {
1206 ret = StrStrW(deadbeefW, StrStrW_cases[i].search);
1207 ok(ret == StrStrW_cases[i].expect,
1208 "[%d] Expected StrStrW to return %p, got %p\n",
1209 i, StrStrW_cases[i].expect, ret);
1210 }
1211 }
1212
1213 static void test_StrStrIA(void)
1214 {
1215 static const char *deadbeefA = "DeAdBeEf";
1216
1217 const struct
1218 {
1219 const char *search;
1220 const char *expect;
1221 } StrStrIA_cases[] =
1222 {
1223 {"", NULL},
1224 {"DeAd", deadbeefA},
1225 {"dead", deadbeefA},
1226 {"AdBe", deadbeefA + 2},
1227 {"adbe", deadbeefA + 2},
1228 {"BeEf", deadbeefA + 4},
1229 {"beef", deadbeefA + 4},
1230 {"cafe", NULL},
1231 };
1232
1233 LPSTR ret;
1234 int i;
1235
1236 /* Tests crash on Win2k */
1237 if (0)
1238 {
1239 ret = StrStrIA(NULL, NULL);
1240 ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret);
1241
1242 ret = StrStrIA(NULL, "");
1243 ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret);
1244
1245 ret = StrStrIA("", NULL);
1246 ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret);
1247 }
1248
1249 ret = StrStrIA("", "");
1250 ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret);
1251
1252 for (i = 0; i < sizeof(StrStrIA_cases)/sizeof(StrStrIA_cases[0]); i++)
1253 {
1254 ret = StrStrIA(deadbeefA, StrStrIA_cases[i].search);
1255 ok(ret == StrStrIA_cases[i].expect,
1256 "[%d] Expected StrStrIA to return %p, got %p\n",
1257 i, StrStrIA_cases[i].expect, ret);
1258 }
1259 }
1260
1261 static void test_StrStrIW(void)
1262 {
1263 static const WCHAR emptyW[] = {0};
1264 static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
1265 static const WCHAR deadW[] = {'D','e','A','d',0};
1266 static const WCHAR dead_lowerW[] = {'d','e','a','d',0};
1267 static const WCHAR adbeW[] = {'A','d','B','e',0};
1268 static const WCHAR adbe_lowerW[] = {'a','d','b','e',0};
1269 static const WCHAR beefW[] = {'B','e','E','f',0};
1270 static const WCHAR beef_lowerW[] = {'b','e','e','f',0};
1271 static const WCHAR cafeW[] = {'c','a','f','e',0};
1272
1273 const struct
1274 {
1275 const WCHAR *search;
1276 const WCHAR *expect;
1277 } StrStrIW_cases[] =
1278 {
1279 {emptyW, NULL},
1280 {deadW, deadbeefW},
1281 {dead_lowerW, deadbeefW},
1282 {adbeW, deadbeefW + 2},
1283 {adbe_lowerW, deadbeefW + 2},
1284 {beefW, deadbeefW + 4},
1285 {beef_lowerW, deadbeefW + 4},
1286 {cafeW, NULL},
1287 };
1288
1289 LPWSTR ret;
1290 int i;
1291
1292 /* Tests crash on Win2k */
1293 if (0)
1294 {
1295 ret = StrStrIW(NULL, NULL);
1296 ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret);
1297
1298 ret = StrStrIW(NULL, emptyW);
1299 ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret);
1300
1301 ret = StrStrIW(emptyW, NULL);
1302 ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret);
1303 }
1304
1305 ret = StrStrIW(emptyW, emptyW);
1306 ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret);
1307
1308 for (i = 0; i < sizeof(StrStrIW_cases)/sizeof(StrStrIW_cases[0]); i++)
1309 {
1310 ret = StrStrIW(deadbeefW, StrStrIW_cases[i].search);
1311 ok(ret == StrStrIW_cases[i].expect,
1312 "[%d] Expected StrStrIW to return %p, got %p\n",
1313 i, StrStrIW_cases[i].expect, ret);
1314 }
1315 }
1316
1317 static void test_StrStrNW(void)
1318 {
1319 static const WCHAR emptyW[] = {0};
1320 static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
1321 static const WCHAR deadW[] = {'D','e','A','d',0};
1322 static const WCHAR dead_lowerW[] = {'d','e','a','d',0};
1323 static const WCHAR adbeW[] = {'A','d','B','e',0};
1324 static const WCHAR adbe_lowerW[] = {'a','d','b','e',0};
1325 static const WCHAR beefW[] = {'B','e','E','f',0};
1326 static const WCHAR beef_lowerW[] = {'b','e','e','f',0};
1327
1328 const struct
1329 {
1330 const WCHAR *search;
1331 const UINT count;
1332 const WCHAR *expect;
1333 } StrStrNW_cases[] =
1334 {
1335 {emptyW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
1336 {deadW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW},
1337 {dead_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
1338 {adbeW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 2},
1339 {adbe_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
1340 {beefW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 4},
1341 {beef_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
1342 {beefW, 0, NULL},
1343 {beefW, 1, NULL},
1344 {beefW, 2, NULL},
1345 {beefW, 3, NULL},
1346 {beefW, 4, NULL},
1347 {beefW, 5, deadbeefW + 4},
1348 {beefW, 6, deadbeefW + 4},
1349 {beefW, 7, deadbeefW + 4},
1350 {beefW, 8, deadbeefW + 4},
1351 {beefW, 9, deadbeefW + 4},
1352 };
1353
1354 LPWSTR ret;
1355 UINT i;
1356
1357 if (!pStrStrNW)
1358 {
1359 win_skip("StrStrNW() is not available\n");
1360 return;
1361 }
1362
1363 ret = pStrStrNW(NULL, NULL, 0);
1364 ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
1365
1366 ret = pStrStrNW(NULL, NULL, 10);
1367 ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
1368
1369 ret = pStrStrNW(NULL, emptyW, 10);
1370 ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
1371
1372 ret = pStrStrNW(emptyW, NULL, 10);
1373 ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
1374
1375 ret = pStrStrNW(emptyW, emptyW, 10);
1376 ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
1377
1378 for (i = 0; i < sizeof(StrStrNW_cases)/sizeof(StrStrNW_cases[0]); i++)
1379 {
1380 ret = pStrStrNW(deadbeefW, StrStrNW_cases[i].search, StrStrNW_cases[i].count);
1381 ok(ret == StrStrNW_cases[i].expect,
1382 "[%d] Expected StrStrNW to return %p, got %p\n",
1383 i, StrStrNW_cases[i].expect, ret);
1384 }
1385
1386 /* StrStrNW accepts counts larger than the search string length but rejects
1387 * counts larger than around 2G. The limit seems to change based on the
1388 * caller executable itself. */
1389 ret = pStrStrNW(deadbeefW, beefW, 100);
1390 ok(ret == deadbeefW + 4, "Expected StrStrNW to return deadbeefW + 4, got %p\n", ret);
1391
1392 if (0)
1393 {
1394 ret = pStrStrNW(deadbeefW, beefW, ~0U);
1395 ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
1396 }
1397 }
1398
1399 static void test_StrStrNIW(void)
1400 {
1401 static const WCHAR emptyW[] = {0};
1402 static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
1403 static const WCHAR deadW[] = {'D','e','A','d',0};
1404 static const WCHAR dead_lowerW[] = {'d','e','a','d',0};
1405 static const WCHAR adbeW[] = {'A','d','B','e',0};
1406 static const WCHAR adbe_lowerW[] = {'a','d','b','e',0};
1407 static const WCHAR beefW[] = {'B','e','E','f',0};
1408 static const WCHAR beef_lowerW[] = {'b','e','e','f',0};
1409 static const WCHAR cafeW[] = {'c','a','f','e',0};
1410
1411 const struct
1412 {
1413 const WCHAR *search;
1414 const UINT count;
1415 const WCHAR *expect;
1416 } StrStrNIW_cases[] =
1417 {
1418 {emptyW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
1419 {deadW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW},
1420 {dead_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW},
1421 {adbeW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 2},
1422 {adbe_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 2},
1423 {beefW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 4},
1424 {beef_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 4},
1425 {cafeW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
1426 {beefW, 0, NULL},
1427 {beefW, 1, NULL},
1428 {beefW, 2, NULL},
1429 {beefW, 3, NULL},
1430 {beefW, 4, NULL},
1431 {beefW, 5, deadbeefW + 4},
1432 {beefW, 6, deadbeefW + 4},
1433 {beefW, 7, deadbeefW + 4},
1434 {beefW, 8, deadbeefW + 4},
1435 {beefW, 9, deadbeefW + 4},
1436 {beef_lowerW, 0, NULL},
1437 {beef_lowerW, 1, NULL},
1438 {beef_lowerW, 2, NULL},
1439 {beef_lowerW, 3, NULL},
1440 {beef_lowerW, 4, NULL},
1441 {beef_lowerW, 5, deadbeefW + 4},
1442 {beef_lowerW, 6, deadbeefW + 4},
1443 {beef_lowerW, 7, deadbeefW + 4},
1444 {beef_lowerW, 8, deadbeefW + 4},
1445 {beef_lowerW, 9, deadbeefW + 4},
1446 };
1447
1448 LPWSTR ret;
1449 UINT i;
1450
1451 if (!pStrStrNIW)
1452 {
1453 win_skip("StrStrNIW() is not available\n");
1454 return;
1455 }
1456
1457 ret = pStrStrNIW(NULL, NULL, 0);
1458 ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
1459
1460 ret = pStrStrNIW(NULL, NULL, 10);
1461 ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
1462
1463 ret = pStrStrNIW(NULL, emptyW, 10);
1464 ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
1465
1466 ret = pStrStrNIW(emptyW, NULL, 10);
1467 ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
1468
1469 ret = pStrStrNIW(emptyW, emptyW, 10);
1470 ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
1471
1472 for (i = 0; i < sizeof(StrStrNIW_cases)/sizeof(StrStrNIW_cases[0]); i++)
1473 {
1474 ret = pStrStrNIW(deadbeefW, StrStrNIW_cases[i].search, StrStrNIW_cases[i].count);
1475 ok(ret == StrStrNIW_cases[i].expect,
1476 "[%d] Expected StrStrNIW to return %p, got %p\n",
1477 i, StrStrNIW_cases[i].expect, ret);
1478 }
1479
1480 /* StrStrNIW accepts counts larger than the search string length but rejects
1481 * counts larger than around 2G. The limit seems to change based on the
1482 * caller executable itself. */
1483 ret = pStrStrNIW(deadbeefW, beefW, 100);
1484 ok(ret == deadbeefW + 4, "Expected StrStrNIW to return deadbeefW + 4, got %p\n", ret);
1485
1486 if (0)
1487 {
1488 ret = pStrStrNIW(deadbeefW, beefW, ~0U);
1489 ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
1490 }
1491 }
1492
1493 static void test_StrCatChainW(void)
1494 {
1495 static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
1496 static const WCHAR deadW[] = {'D','e','A','d',0};
1497 static const WCHAR beefW[] = {'B','e','E','f',0};
1498
1499 WCHAR buf[32 + 1];
1500 DWORD ret;
1501
1502 if (!pStrCatChainW)
1503 {
1504 win_skip("StrCatChainW is not available\n");
1505 return;
1506 }
1507
1508 /* Test with NULL buffer */
1509 ret = pStrCatChainW(NULL, 0, 0, beefW);
1510 ok(ret == 0, "Expected StrCatChainW to return 0, got %u\n", ret);
1511
1512 /* Test with empty buffer */
1513 memset(buf, 0x11, sizeof(buf));
1514 ret = pStrCatChainW(buf, 0, 0, beefW);
1515 ok(ret == 0, "Expected StrCatChainW to return 0, got %u\n", ret);
1516 ok(buf[0] == 0x1111, "Expected buf[0] = 0x1111, got %x\n", buf[0]);
1517
1518 memcpy(buf, deadbeefW, sizeof(deadbeefW));
1519 ret = pStrCatChainW(buf, 0, -1, beefW);
1520 ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
1521 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1522
1523 /* Append data to existing string with offset = -1 */
1524 memset(buf, 0x11, sizeof(buf));
1525 ret = pStrCatChainW(buf, 32, 0, deadW);
1526 ok(ret == 4, "Expected StrCatChainW to return 4, got %u\n", ret);
1527 ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1528
1529 ret = pStrCatChainW(buf, 32, -1, beefW);
1530 ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
1531 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1532
1533 /* Append data at a fixed offset */
1534 memset(buf, 0x11, sizeof(buf));
1535 ret = pStrCatChainW(buf, 32, 0, deadW);
1536 ok(ret == 4, "Expected StrCatChainW to return 4, got %u\n", ret);
1537 ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1538
1539 ret = pStrCatChainW(buf, 32, 4, beefW);
1540 ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
1541 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1542
1543 /* Buffer exactly sufficient for string + terminating null */
1544 memset(buf, 0x11, sizeof(buf));
1545 ret = pStrCatChainW(buf, 5, 0, deadW);
1546 ok(ret == 4, "Expected StrCatChainW to return 4, got %u\n", ret);
1547 ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1548
1549 /* Buffer too small, string will be truncated */
1550 memset(buf, 0x11, sizeof(buf));
1551 ret = pStrCatChainW(buf, 4, 0, deadW);
1552 if (ret == 4)
1553 {
1554 /* Windows 2000 and XP uses a slightly different implementation
1555 * for StrCatChainW, which doesn't ensure that strings are null-
1556 * terminated. Skip test if we detect such an implementation. */
1557 win_skip("Windows2000/XP behaviour detected for StrCatChainW, skipping tests\n");
1558 return;
1559 }
1560 ok(ret == 3, "Expected StrCatChainW to return 3, got %u\n", ret);
1561 ok(!memcmp(buf, deadW, 3 * sizeof(WCHAR)), "Buffer contains wrong data\n");
1562 ok(!buf[3], "String is not nullterminated\n");
1563 ok(buf[4] == 0x1111, "Expected buf[4] = 0x1111, got %x\n", buf[4]);
1564
1565 /* Overwrite part of an existing string */
1566 ret = pStrCatChainW(buf, 4, 1, beefW);
1567 ok(ret == 3, "Expected StrCatChainW to return 3, got %u\n", ret);
1568 ok(buf[0] == 'D', "Expected buf[0] = 'D', got %x\n", buf[0]);
1569 ok(buf[1] == 'B', "Expected buf[1] = 'B', got %x\n", buf[1]);
1570 ok(buf[2] == 'e', "Expected buf[2] = 'e', got %x\n", buf[2]);
1571 ok(!buf[3], "String is not nullterminated\n");
1572 ok(buf[4] == 0x1111, "Expected buf[4] = 0x1111, got %x\n", buf[4]);
1573
1574 /* Test appending to full buffer */
1575 memset(buf, 0x11, sizeof(buf));
1576 memcpy(buf, deadbeefW, sizeof(deadbeefW));
1577 memcpy(buf + 9, deadW, sizeof(deadW));
1578 ret = pStrCatChainW(buf, 9, 8, beefW);
1579 ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
1580 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1581 ok(!memcmp(buf + 9, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1582
1583 /* Offset points at the end of the buffer */
1584 ret = pStrCatChainW(buf, 9, 9, beefW);
1585 ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
1586 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1587 ok(!memcmp(buf + 9, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1588
1589 /* Offset points outside of the buffer */
1590 ret = pStrCatChainW(buf, 9, 10, beefW);
1591 ok(ret == 10, "Expected StrCatChainW to return 10, got %u\n", ret);
1592 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1593 ok(!memcmp(buf + 9, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1594
1595 /* The same but without nullterminated string */
1596 memcpy(buf, deadbeefW, sizeof(deadbeefW));
1597 ret = pStrCatChainW(buf, 5, -1, deadW);
1598 ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
1599 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1600
1601 ret = pStrCatChainW(buf, 5, 5, deadW);
1602 ok(ret == 4, "Expected StrCatChainW to return 4, got %u\n", ret);
1603 ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1604 ok(buf[5] == 'e', "Expected buf[5] = 'e', got %x\n", buf[5]);
1605
1606 ret = pStrCatChainW(buf, 5, 6, deadW);
1607 ok(ret == 6, "Expected StrCatChainW to return 6, got %u\n", ret);
1608 ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1609 ok(buf[5] == 'e', "Expected buf[5] = 'e', got %x\n", buf[5]);
1610 }
1611
1612 START_TEST(string)
1613 {
1614 HMODULE hShlwapi;
1615 CHAR thousandDelim[8];
1616 CHAR decimalDelim[8];
1617 CoInitialize(0);
1618
1619 GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousandDelim, 8);
1620 GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimalDelim, 8);
1621
1622 hShlwapi = GetModuleHandleA("shlwapi");
1623 pChrCmpIA = (void *)GetProcAddress(hShlwapi, "ChrCmpIA");
1624 pChrCmpIW = (void *)GetProcAddress(hShlwapi, "ChrCmpIW");
1625 pIntlStrEqWorkerA = (void *)GetProcAddress(hShlwapi, "IntlStrEqWorkerA");
1626 pIntlStrEqWorkerW = (void *)GetProcAddress(hShlwapi, "IntlStrEqWorkerW");
1627 pSHAnsiToAnsi = (void *)GetProcAddress(hShlwapi, (LPSTR)345);
1628 pSHUnicodeToUnicode = (void *)GetProcAddress(hShlwapi, (LPSTR)346);
1629 pStrCatBuffA = (void *)GetProcAddress(hShlwapi, "StrCatBuffA");
1630 pStrCatBuffW = (void *)GetProcAddress(hShlwapi, "StrCatBuffW");
1631 pStrCatChainW = (void *)GetProcAddress(hShlwapi, "StrCatChainW");
1632 pStrCpyNXA = (void *)GetProcAddress(hShlwapi, (LPSTR)399);
1633 pStrCpyNXW = (void *)GetProcAddress(hShlwapi, (LPSTR)400);
1634 pStrChrNW = (void *)GetProcAddress(hShlwapi, "StrChrNW");
1635 pStrFormatByteSize64A = (void *)GetProcAddress(hShlwapi, "StrFormatByteSize64A");
1636 pStrFormatKBSizeA = (void *)GetProcAddress(hShlwapi, "StrFormatKBSizeA");
1637 pStrFormatKBSizeW = (void *)GetProcAddress(hShlwapi, "StrFormatKBSizeW");
1638 pStrIsIntlEqualA = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualA");
1639 pStrIsIntlEqualW = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualW");
1640 pStrPBrkW = (void *)GetProcAddress(hShlwapi, "StrPBrkW");
1641 pStrRChrA = (void *)GetProcAddress(hShlwapi, "StrRChrA");
1642 pStrRetToBSTR = (void *)GetProcAddress(hShlwapi, "StrRetToBSTR");
1643 pStrRetToBufA = (void *)GetProcAddress(hShlwapi, "StrRetToBufA");
1644 pStrRetToBufW = (void *)GetProcAddress(hShlwapi, "StrRetToBufW");
1645 pStrStrNW = (void *)GetProcAddress(hShlwapi, "StrStrNW");
1646 pStrStrNIW = (void *)GetProcAddress(hShlwapi, "StrStrNIW");
1647 pwnsprintfA = (void *)GetProcAddress(hShlwapi, "wnsprintfA");
1648 pwnsprintfW = (void *)GetProcAddress(hShlwapi, "wnsprintfW");
1649 pStrToInt64ExA = (void *)GetProcAddress(hShlwapi, "StrToInt64ExA");
1650 pStrToInt64ExW = (void *)GetProcAddress(hShlwapi, "StrToInt64ExW");
1651
1652 test_StrChrA();
1653 test_StrChrW();
1654 test_StrChrIA();
1655 test_StrChrIW();
1656 test_StrRChrA();
1657 test_StrRChrW();
1658 test_StrCpyW();
1659 test_StrChrNW();
1660 test_StrToIntA();
1661 test_StrToIntW();
1662 test_StrToIntExA();
1663 test_StrToIntExW();
1664 test_StrToInt64ExA();
1665 test_StrToInt64ExW();
1666 test_StrDupA();
1667
1668 /* language-dependent test */
1669 if (is_lang_english() && is_locale_english())
1670 {
1671 test_StrFormatByteSize64A();
1672 test_StrFormatKBSizeA();
1673 test_StrFormatKBSizeW();
1674 }
1675 else
1676 skip("An English UI and locale is required for the StrFormat*Size tests\n");
1677 if (is_lang_english())
1678 test_StrFromTimeIntervalA();
1679 else
1680 skip("An English UI is required for the StrFromTimeInterval tests\n");
1681
1682 test_StrCmpA();
1683 test_StrCmpW();
1684 test_StrRetToBSTR();
1685 test_StrCpyNXA();
1686 test_StrCpyNXW();
1687 test_StrRStrI();
1688 test_SHAnsiToAnsi();
1689 test_SHUnicodeToUnicode();
1690 test_StrXXX_overflows();
1691 test_StrStrA();
1692 test_StrStrW();
1693 test_StrStrIA();
1694 test_StrStrIW();
1695 test_StrStrNW();
1696 test_StrStrNIW();
1697 test_StrCatChainW();
1698
1699 CoUninitialize();
1700 }