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