Implement A->W call for GetNamedSecurityInfo.
[wine] / dlls / shlwapi / tests / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include <stdlib.h>
21 #include <stdio.h>
22
23 #define NONAMELESSUNION
24 #define NONAMELESSSTRUCT
25 #include "wine/test.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "winnls.h"
29 #define NO_SHLWAPI_REG
30 #define NO_SHLWAPI_PATH
31 #define NO_SHLWAPI_GDI
32 #define NO_SHLWAPI_STREAM
33 #include "shlwapi.h"
34 #include "shtypes.h"
35
36 static HRESULT (WINAPI *ptr_StrRetToBSTR) (STRRET*, void*, BSTR*);
37
38 static inline int strcmpW(const WCHAR *str1, const WCHAR *str2)
39 {
40     while (*str1 && (*str1 == *str2)) { str1++; str2++; }
41     return *str1 - *str2;
42 }
43
44 /* StrToInt/StrToIntEx results */
45 typedef struct tagStrToIntResult
46 {
47   const char* string;
48   int str_to_int;
49   int str_to_int_ex;
50   int str_to_int_hex;
51 } StrToIntResult;
52
53 static const StrToIntResult StrToInt_results[] = {
54      { "1099", 1099, 1099, 1099 },
55      { "+88987", 0, 88987, 88987 },
56      { "012", 12, 12, 12 },
57      { "-55", -55, -55, -55 },
58      { "-0", 0, 0, 0 },
59      { "0x44ff", 0, 0, 0x44ff },
60      { "+0x44f4", 0, 0, 0x44f4 },
61      { "-0x44fd", 0, 0, 0x44fd },
62      { "+ 88987", 0, 0, 0 },
63      { "- 55", 0, 0, 0 },
64      { "- 0", 0, 0, 0 },
65      { "+ 0x44f4", 0, 0, 0 },
66      { "--0x44fd", 0, 0, 0 },
67      { " 1999", 0, 1999, 1999 },
68      { " +88987", 0, 88987, 88987 },
69      { " 012", 0, 12, 12 },
70      { " -55", 0, -55, -55 },
71      { " 0x44ff", 0, 0, 0x44ff },
72      { " +0x44f4", 0, 0, 0x44f4 },
73      { " -0x44fd", 0, 0, 0x44fd },
74      { NULL, 0, 0, 0 }
75 };
76
77 /* pStrFormatByteSize64/StrFormatKBSize results */
78 typedef struct tagStrFormatSizeResult
79 {
80   LONGLONG value;
81   const char* byte_size_64;
82   const char* kb_size;
83 } StrFormatSizeResult;
84
85
86 static const StrFormatSizeResult StrFormatSize_results[] = {
87   { -1023, "-1023 bytes", "0 KB"},
88   { -24, "-24 bytes", "0 KB"},
89   { 309, "309 bytes", "1 KB"},
90   { 10191, "9.95 KB", "10 KB"},
91   { 100353, "98.0 KB", "99 KB"},
92   { 1022286, "998 KB", "999 KB"},
93   { 1046862, "0.99 MB", "1,023 KB"},
94   { 1048574619, "999 MB", "1,023,999 KB"},
95   { 1073741775, "0.99 GB", "1,048,576 KB"},
96   { ((LONGLONG)0x000000f9 << 32) | 0xfffff94e, "999 GB", "1,048,575,999 KB"},
97   { ((LONGLONG)0x000000ff << 32) | 0xfffffa9b, "0.99 TB", "1,073,741,823 KB"},
98   { ((LONGLONG)0x0003e7ff << 32) | 0xfffffa9b, "999 TB", "1,073,741,823,999 KB"},
99   { ((LONGLONG)0x0003ffff << 32) | 0xfffffbe8, "0.99 PB", "1,099,511,627,775 KB"},
100   { ((LONGLONG)0x0f9fffff << 32) | 0xfffffd35, "999 PB", "1,099,511,627,776,000 KB"},
101   { ((LONGLONG)0x0fffffff << 32) | 0xfffffa9b, "0.99 EB", "1,125,899,906,842,623 KB"},
102   { 0, NULL, NULL }
103 };
104
105 /* StrFormatByteSize64/StrFormatKBSize results */
106 typedef struct tagStrFromTimeIntervalResult
107 {
108   DWORD ms;
109   int   digits;
110   const char* time_interval;
111 } StrFromTimeIntervalResult;
112
113
114 static const StrFromTimeIntervalResult StrFromTimeInterval_results[] = {
115   { 1, 1, " 0 sec" },
116   { 1, 2, " 0 sec" },
117   { 1, 3, " 0 sec" },
118   { 1, 4, " 0 sec" },
119   { 1, 5, " 0 sec" },
120   { 1, 6, " 0 sec" },
121   { 1, 7, " 0 sec" },
122
123   { 1000000, 1, " 10 min" },
124   { 1000000, 2, " 16 min" },
125   { 1000000, 3, " 16 min 40 sec" },
126   { 1000000, 4, " 16 min 40 sec" },
127   { 1000000, 5, " 16 min 40 sec" },
128   { 1000000, 6, " 16 min 40 sec" },
129   { 1000000, 7, " 16 min 40 sec" },
130
131   { 1999999, 1, " 30 min" },
132   { 1999999, 2, " 33 min" },
133   { 1999999, 3, " 33 min 20 sec" },
134   { 1999999, 4, " 33 min 20 sec" },
135   { 1999999, 5, " 33 min 20 sec" },
136   { 1999999, 6, " 33 min 20 sec" },
137   { 1999999, 7, " 33 min 20 sec" },
138
139   { 3999997, 1, " 1 hr" },
140   { 3999997, 2, " 1 hr 6 min" },
141   { 3999997, 3, " 1 hr 6 min 40 sec" },
142   { 3999997, 4, " 1 hr 6 min 40 sec" },
143   { 3999997, 5, " 1 hr 6 min 40 sec" },
144   { 3999997, 6, " 1 hr 6 min 40 sec" },
145   { 3999997, 7, " 1 hr 6 min 40 sec" },
146
147   { 149999851, 7, " 41 hr 40 min 0 sec" },
148   { 150999850, 1, " 40 hr" },
149   { 150999850, 2, " 41 hr" },
150   { 150999850, 3, " 41 hr 50 min" },
151   { 150999850, 4, " 41 hr 56 min" },
152   { 150999850, 5, " 41 hr 56 min 40 sec" },
153   { 150999850, 6, " 41 hr 56 min 40 sec" },
154   { 150999850, 7, " 41 hr 56 min 40 sec" },
155
156   { 493999507, 1, " 100 hr" },
157   { 493999507, 2, " 130 hr" },
158   { 493999507, 3, " 137 hr" },
159   { 493999507, 4, " 137 hr 10 min" },
160   { 493999507, 5, " 137 hr 13 min" },
161   { 493999507, 6, " 137 hr 13 min 20 sec" },
162   { 493999507, 7, " 137 hr 13 min 20 sec" },
163
164   { 0, 0, NULL }
165 };
166
167 static void test_StrChrA(void)
168 {
169   char string[129];
170   WORD count;
171
172   /* this test crashes on win2k SP4 */
173   /*ok(!StrChrA(NULL,'\0'), "found a character in a NULL string!\n");*/
174
175   for (count = 32; count < 128; count++)
176     string[count] = (char)count;
177   string[128] = '\0';
178
179   for (count = 32; count < 128; count++)
180   {
181     LPSTR result = StrChrA(string+32, count);
182     ok(result - string == count,
183         "found char '%c' in wrong place: got %d, expected %d\n",
184         count, result - string, count);
185   }
186
187   for (count = 32; count < 128; count++)
188   {
189     LPSTR result = StrChrA(string+count+1, count);
190     ok(!result, "found char '%c' not in the string\n", count);
191   }
192 }
193
194 static void test_StrChrW(void)
195 {
196   WCHAR string[16385];
197   WORD count;
198
199   /* this test crashes on win2k SP4 */
200   /*ok(!StrChrW(NULL,'\0'), "found a character in a NULL string!\n");*/
201
202   for (count = 32; count < 16384; count++)
203     string[count] = count;
204   string[16384] = '\0';
205
206   for (count = 32; count < 16384; count++)
207   {
208     LPWSTR result = StrChrW(string+32, count);
209     ok((result - string) == count, "found char %d in wrong place\n", count);
210   }
211
212   for (count = 32; count < 16384; count++)
213   {
214     LPWSTR result = StrChrW(string+count+1, count);
215     ok(!result, "found char not in the string\n");
216   }
217 }
218
219 static void test_StrChrIA(void)
220 {
221   char string[129];
222   WORD count;
223
224   /* this test crashes on win2k SP4 */
225   /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/
226
227   for (count = 32; count < 128; count++)
228     string[count] = (char)count;
229   string[128] = '\0';
230
231   for (count = 'A'; count <= 'X'; count++)
232   {
233     LPSTR result = StrChrIA(string+32, count);
234
235     ok(result - string == count, "found char '%c' in wrong place\n", count);
236     ok(StrChrIA(result, count)!=NULL, "didn't find lowercase '%c'\n", count);
237   }
238
239   for (count = 'a'; count < 'z'; count++)
240   {
241     LPSTR result = StrChrIA(string+count+1, count);
242     ok(!result, "found char not in the string\n");
243   }
244 }
245
246 static void test_StrChrIW(void)
247 {
248   WCHAR string[129];
249   WORD count;
250
251   /* this test crashes on win2k SP4 */
252   /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/
253
254   for (count = 32; count < 128; count++)
255     string[count] = count;
256   string[128] = '\0';
257
258   for (count = 'A'; count <= 'X'; count++)
259   {
260     LPWSTR result = StrChrIW(string+32, count);
261
262     ok(result - string == count, "found char '%c' in wrong place\n", count);
263     ok(StrChrIW(result, count)!=NULL, "didn't find lowercase '%c'\n", count);
264   }
265
266   for (count = 'a'; count < 'z'; count++)
267   {
268     LPWSTR result = StrChrIW(string+count+1, count);
269     ok(!result, "found char not in the string\n");
270   }
271 }
272
273 static void test_StrRChrA(void)
274 {
275   char string[129];
276   WORD count;
277
278   /* this test crashes on win2k SP4 */
279   /*ok(!StrRChrA(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/
280
281   for (count = 32; count < 128; count++)
282     string[count] = (char)count;
283   string[128] = '\0';
284
285   for (count = 32; count < 128; count++)
286   {
287     LPSTR result = StrRChrA(string+32, NULL, count);
288     ok(result - string == count, "found char %d in wrong place\n", count);
289   }
290
291   for (count = 32; count < 128; count++)
292   {
293     LPSTR result = StrRChrA(string+count+1, NULL, count);
294     ok(!result, "found char not in the string\n");
295   }
296
297   for (count = 32; count < 128; count++)
298   {
299     LPSTR result = StrRChrA(string+count+1, string + 127, count);
300     ok(!result, "found char not in the string\n");
301   }
302 }
303
304 static void test_StrRChrW(void)
305 {
306   WCHAR string[129];
307   WORD count;
308
309   /* this test crashes on win2k SP4 */
310   /*ok(!StrRChrW(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/
311
312   for (count = 32; count < 128; count++)
313     string[count] = count;
314   string[128] = '\0';
315
316   for (count = 32; count < 128; count++)
317   {
318     LPWSTR result = StrRChrW(string+32, NULL, count);
319     ok(result - string == count,
320         "found char %d in wrong place: got %d, expected %d\n",
321         count, result - string, count);
322   }
323
324   for (count = 32; count < 128; count++)
325   {
326     LPWSTR result = StrRChrW(string+count+1, NULL, count);
327     ok(!result, "found char %d not in the string\n", count);
328   }
329
330   for (count = 32; count < 128; count++)
331   {
332     LPWSTR result = StrRChrW(string+count+1, string + 127, count);
333     ok(!result, "found char %d not in the string\n", count);
334   }
335 }
336
337 static void test_StrCpyW(void)
338 {
339   WCHAR szSrc[256];
340   WCHAR szBuff[256];
341   const StrFormatSizeResult* result = StrFormatSize_results;
342
343
344   while(result->value)
345   {
346     MultiByteToWideChar(0,0,result->byte_size_64,-1,szSrc,sizeof(szSrc)/sizeof(WCHAR));
347
348     StrCpyW(szBuff, szSrc);
349     ok(!StrCmpW(szSrc, szBuff), "Copied string %s wrong\n", result->byte_size_64);
350     result++;
351   }
352 }
353
354
355 static void test_StrToIntA(void)
356 {
357   const StrToIntResult *result = StrToInt_results;
358   int return_val;
359
360   while (result->string)
361   {
362     return_val = StrToIntA(result->string);
363     ok(return_val == result->str_to_int, "converted '%s' wrong (%d)\n",
364        result->string, return_val);
365     result++;
366   }
367 }
368
369 static void test_StrToIntW(void)
370 {
371   WCHAR szBuff[256];
372   const StrToIntResult *result = StrToInt_results;
373   int return_val;
374
375   while (result->string)
376   {
377     MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
378     return_val = StrToIntW(szBuff);
379     ok(return_val == result->str_to_int, "converted '%s' wrong (%d)\n",
380        result->string, return_val);
381     result++;
382   }
383 }
384
385 static void test_StrToIntExA(void)
386 {
387   const StrToIntResult *result = StrToInt_results;
388   int return_val;
389   BOOL bRet;
390
391   while (result->string)
392   {
393     return_val = -1;
394     bRet = StrToIntExA(result->string,0,&return_val);
395     ok(!bRet || return_val != -1, "No result returned from '%s'\n",
396        result->string);
397     if (bRet)
398       ok(return_val == result->str_to_int_ex, "converted '%s' wrong (%d)\n",
399          result->string, return_val);
400     result++;
401   }
402
403   result = StrToInt_results;
404   while (result->string)
405   {
406     return_val = -1;
407     bRet = StrToIntExA(result->string,STIF_SUPPORT_HEX,&return_val);
408     ok(!bRet || return_val != -1, "No result returned from '%s'\n",
409        result->string);
410     if (bRet)
411       ok(return_val == result->str_to_int_hex, "converted '%s' wrong (%d)\n",
412          result->string, return_val);
413     result++;
414   }
415 }
416
417 static void test_StrToIntExW(void)
418 {
419   WCHAR szBuff[256];
420   const StrToIntResult *result = StrToInt_results;
421   int return_val;
422   BOOL bRet;
423
424   while (result->string)
425   {
426     return_val = -1;
427     MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
428     bRet = StrToIntExW(szBuff, 0, &return_val);
429     ok(!bRet || return_val != -1, "No result returned from '%s'\n",
430        result->string);
431     if (bRet)
432       ok(return_val == result->str_to_int_ex, "converted '%s' wrong (%d)\n",
433          result->string, return_val);
434     result++;
435   }
436
437   result = StrToInt_results;
438   while (result->string)
439   {
440     return_val = -1;
441     MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
442     bRet = StrToIntExW(szBuff, STIF_SUPPORT_HEX, &return_val);
443     ok(!bRet || return_val != -1, "No result returned from '%s'\n",
444        result->string);
445     if (bRet)
446       ok(return_val == result->str_to_int_hex, "converted '%s' wrong (%d)\n",
447          result->string, return_val);
448     result++;
449   }
450 }
451
452 static void test_StrDupA()
453 {
454   LPSTR lpszStr;
455   const StrFormatSizeResult* result = StrFormatSize_results;
456
457   while(result->value)
458   {
459     lpszStr = StrDupA(result->byte_size_64);
460
461     ok(lpszStr != NULL, "Dup failed\n");
462     if (lpszStr)
463     {
464       ok(!strcmp(result->byte_size_64, lpszStr), "Copied string wrong\n");
465       LocalFree((HLOCAL)lpszStr);
466     }
467     result++;
468   }
469
470   /* Later versions of shlwapi return NULL for this, but earlier versions
471    * returned an empty string (as Wine does).
472    */
473   lpszStr = StrDupA(NULL);
474   ok(lpszStr == NULL || *lpszStr == '\0', "NULL string returned %p\n", lpszStr);
475 }
476
477 static void test_StrFormatByteSize64A(void)
478 {
479 /* this test fails on locales which do not use '.' as a decimal separator */
480 #if 0
481   char szBuff[256];
482   const StrFormatSizeResult* result = StrFormatSize_results;
483
484   while(result->value)
485   {
486     StrFormatByteSize64A(result->value, szBuff, 256);
487
488     ok(!strcmp(result->byte_size_64, szBuff),
489         "Formatted %lx%08lx wrong: got %s, expected %s\n",
490        (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->byte_size_64);
491
492     result++;
493   }
494 #endif
495 }
496
497 static void test_StrFormatKBSizeW(void)
498 {
499 /* FIXME: Awaiting NLS fixes in kernel before these succeed */
500 #if 0
501   WCHAR szBuffW[256];
502   char szBuff[256];
503   const StrFormatSizeResult* result = StrFormatSize_results;
504
505   while(result->value)
506   {
507     StrFormatKBSizeW(result->value, szBuffW, 256);
508     WideCharToMultiByte(0,0,szBuffW,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR),0,0);
509     ok(!strcmp(result->kb_size, szBuff),
510         "Formatted %lx%08lx wrong: got %s, expected %s\n",
511        (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
512     result++;
513   }
514 #endif
515 }
516
517 static void test_StrFormatKBSizeA(void)
518 {
519 /* this test fails on locales which do not use '.' as a decimal separator */
520 #if 0
521   char szBuff[256];
522   const StrFormatSizeResult* result = StrFormatSize_results;
523
524   while(result->value)
525   {
526     StrFormatKBSizeA(result->value, szBuff, 256);
527
528     ok(!strcmp(result->kb_size, szBuff),
529         "Formatted %lx%08lx wrong: got %s, expected %s\n",
530        (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
531     result++;
532   }
533 #endif
534 }
535
536 void test_StrFromTimeIntervalA(void)
537 {
538   char szBuff[256];
539   const StrFromTimeIntervalResult* result = StrFromTimeInterval_results;
540
541   while(result->ms)
542   {
543     StrFromTimeIntervalA(szBuff, 256, result->ms, result->digits);
544
545     ok(!strcmp(result->time_interval, szBuff), "Formatted %ld %d wrong\n",
546        result->ms, result->digits);
547     result++;
548   }
549 }
550
551 void test_StrCmpA(void)
552 {
553   static const char str1[] = {'a','b','c','d','e','f'};
554   static const char str2[] = {'a','B','c','d','e','f'};
555   ok(0 != StrCmpNA(str1, str2, 6), "StrCmpNA is case-insensitive\n");
556   ok(0 == StrCmpNIA(str1, str2, 6), "StrCmpNIA is case-sensitive\n");
557   ok(!ChrCmpIA('a', 'a'), "ChrCmpIA doesn't work at all!\n");
558   ok(!ChrCmpIA('b', 'B'), "ChrCmpIA is not case-insensitive\n");
559   ok(ChrCmpIA('a', 'z'), "ChrCmpIA believes that a == z!\n");
560
561   ok(StrIsIntlEqualA(FALSE, str1, str2, 5), "StrIsIntlEqualA(FALSE,...) isn't case-insensitive\n");
562   ok(!StrIsIntlEqualA(TRUE, str1, str2, 5), "StrIsIntlEqualA(TRUE,...) isn't case-sensitive\n");
563
564   ok(IntlStrEqWorkerA(FALSE, str1, str2, 5), "IntlStrEqWorkerA(FALSE,...) isn't case-insensitive\n");
565   ok(!IntlStrEqWorkerA(TRUE, str1, str2, 5), "IntlStrEqWorkerA(TRUE,...) isn't case-sensitive\n");
566 }
567
568 void test_StrCmpW(void)
569 {
570   static const WCHAR str1[] = {'a','b','c','d','e','f'};
571   static const WCHAR str2[] = {'a','B','c','d','e','f'};
572   ok(0 != StrCmpNW(str1, str2, 5), "StrCmpNW is case-insensitive\n");
573   ok(0 == StrCmpNIW(str1, str2, 5), "StrCmpNIW is case-sensitive\n");
574   ok(!ChrCmpIW('a', 'a'), "ChrCmpIW doesn't work at all!\n");
575   ok(!ChrCmpIW('b', 'B'), "ChrCmpIW is not case-insensitive\n");
576   ok(ChrCmpIW('a', 'z'), "ChrCmpIW believes that a == z!\n");
577
578   ok(StrIsIntlEqualW(FALSE, str1, str2, 5), "StrIsIntlEqualW(FALSE,...) isn't case-insensitive\n");
579   ok(!StrIsIntlEqualW(TRUE, str1, str2, 5), "StrIsIntlEqualW(TRUE,...) isn't case-sensitive\n");
580
581   ok(IntlStrEqWorkerW(FALSE, str1, str2, 5), "IntlStrEqWorkerW(FALSE,...) isn't case-insensitive\n");
582   ok(!IntlStrEqWorkerW(TRUE, str1, str2, 5), "IntlStrEqWorkerW(TRUE,...) isn't case-sensitive\n");
583 }
584
585 static WCHAR *CoDupStrW(const char* src)
586 {
587   INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
588   WCHAR* szTemp = (WCHAR*)CoTaskMemAlloc(len * sizeof(WCHAR));
589   MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
590   return szTemp;
591 }
592
593 static void test_StrRetToBSTR(void)
594 {
595     HMODULE module;
596     static const WCHAR szTestW[] = { 'T','e','s','t','\0' };
597     ITEMIDLIST iidl[10];
598     BSTR bstr;
599     STRRET strret;
600     HRESULT ret;
601
602     module = GetModuleHandleA("shlwapi");
603     if (!module) return;
604     ptr_StrRetToBSTR = (void *)GetProcAddress(module, "StrRetToBSTR");
605     if (!ptr_StrRetToBSTR) return;
606
607     strret.uType = STRRET_WSTR;
608     strret.u.pOleStr = CoDupStrW("Test");
609     bstr = 0;
610     ret = ptr_StrRetToBSTR(&strret, NULL, &bstr);
611     ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
612        "STRRET_WSTR: dup failed, ret=0x%08lx, bstr %p\n", ret, bstr);
613     if (bstr)
614       SysFreeString(bstr);
615
616     strret.uType = STRRET_CSTR;
617     lstrcpyA(strret.u.cStr, "Test");
618     ret = ptr_StrRetToBSTR(&strret, NULL, &bstr);
619     ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
620        "STRRET_CSTR: dup failed, ret=0x%08lx, bstr %p\n", ret, bstr);
621     if (bstr)
622       SysFreeString(bstr);
623
624     strret.uType = STRRET_OFFSET;
625     strret.u.uOffset = 1;
626     strcpy((char*)&iidl, " Test");
627     ret = ptr_StrRetToBSTR(&strret, iidl, &bstr);
628     ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
629        "STRRET_OFFSET: dup failed, ret=0x%08lx, bstr %p\n", ret, bstr);
630     if (bstr)
631       SysFreeString(bstr);
632
633     /* Native crashes if str is NULL */
634 }
635
636 START_TEST(string)
637 {
638   CoInitialize(0);
639
640   test_StrChrA();
641   test_StrChrW();
642   test_StrChrIA();
643   test_StrChrIW();
644   test_StrRChrA();
645   test_StrRChrW();
646   test_StrCpyW();
647   test_StrToIntA();
648   test_StrToIntW();
649   test_StrToIntExA();
650   test_StrToIntExW();
651   test_StrDupA();
652   test_StrFormatByteSize64A();
653   test_StrFormatKBSizeA();
654   test_StrFormatKBSizeW();
655   test_StrFromTimeIntervalA();
656   test_StrCmpA();
657   test_StrCmpW();
658   test_StrRetToBSTR();
659 }