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