2 * Shlwapi string functions
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/port.h"
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
34 #define NO_SHLWAPI_REG
35 #define NO_SHLWAPI_STREAM
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(shell);
49 extern HINSTANCE shlwapi_hInstance;
51 static HRESULT _SHStrDupAA(LPCSTR,LPSTR*);
52 static HRESULT _SHStrDupAW(LPCWSTR,LPSTR*);
55 static void FillNumberFmt(NUMBERFMTW *fmt, LPWSTR decimal_buffer, int decimal_bufwlen,
56 LPWSTR thousand_buffer, int thousand_bufwlen)
61 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR));
62 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->NegativeOrder)/sizeof(WCHAR));
64 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, decimal_bufwlen);
65 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen);
66 fmt->lpThousandSep = thousand_buffer;
67 fmt->lpDecimalSep = decimal_buffer;
70 * Converting grouping string to number as described on
71 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
74 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping)/sizeof(WCHAR));
75 for (c = grouping; *c; c++)
76 if (*c >= '0' && *c < '9')
79 fmt->Grouping += *c - '0';
82 if (fmt->Grouping % 10 == 0)
88 /*************************************************************************
89 * FormatInt [internal]
91 * Format an integer according to the current locale
94 * The number of characters written on success or 0 on failure
96 static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf)
99 WCHAR decimal[8], thousand[8];
102 BOOL neg = (qdwValue < 0);
104 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
105 thousand, sizeof thousand / sizeof (WCHAR));
111 *(--c) = '0' + (qdwValue%10);
113 } while (qdwValue > 0);
117 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
120 /*************************************************************************
121 * FormatDouble [internal]
123 * Format an integer according to the current locale. Prints the specified number of digits
124 * after the decimal point
127 * The number of characters written on success or 0 on failure
129 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
131 static const WCHAR flfmt[] = {'%','f',0};
134 WCHAR decimal[8], thousand[8];
136 snprintfW(buf, 64, flfmt, value);
138 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
139 thousand, sizeof thousand / sizeof (WCHAR));
140 fmt.NumDigits = decimals;
141 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
144 /*************************************************************************
145 * SHLWAPI_ChrCmpHelperA
147 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
150 * Both this function and its Unicode counterpart are very inefficient. To
151 * fix this, CompareString must be completely implemented and optimised
152 * first. Then the core character test can be taken out of that function and
153 * placed here, so that it need never be called at all. Until then, do not
154 * attempt to optimise this code unless you are willing to test that it
155 * still performs correctly.
157 static BOOL SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
159 char str1[3], str2[3];
161 str1[0] = LOBYTE(ch1);
162 if (IsDBCSLeadByte(str1[0]))
164 str1[1] = HIBYTE(ch1);
170 str2[0] = LOBYTE(ch2);
171 if (IsDBCSLeadByte(str2[0]))
173 str2[1] = HIBYTE(ch2);
179 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
182 /*************************************************************************
185 * Internal helper function.
187 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
189 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
192 /*************************************************************************
193 * ChrCmpIA (SHLWAPI.385)
195 * Compare two characters, ignoring case.
198 * ch1 [I] First character to compare
199 * ch2 [I] Second character to compare
202 * FALSE, if the characters are equal.
203 * Non-zero otherwise.
205 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
207 TRACE("(%d,%d)\n", ch1, ch2);
209 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
212 /*************************************************************************
213 * ChrCmpIW [SHLWAPI.386]
217 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
219 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, &ch1, 1, &ch2, 1) - 2;
222 /*************************************************************************
223 * StrChrA [SHLWAPI.@]
225 * Find a given character in a string.
228 * lpszStr [I] String to search in.
229 * ch [I] Character to search for.
232 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
234 * Failure: NULL, if any arguments are invalid.
236 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
238 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
244 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
245 return (LPSTR)lpszStr;
246 lpszStr = CharNextA(lpszStr);
252 /*************************************************************************
253 * StrChrW [SHLWAPI.@]
257 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
259 LPWSTR lpszRet = NULL;
261 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
264 lpszRet = strchrW(lpszStr, ch);
268 /*************************************************************************
269 * StrChrIA [SHLWAPI.@]
271 * Find a given character in a string, ignoring case.
274 * lpszStr [I] String to search in.
275 * ch [I] Character to search for.
278 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
280 * Failure: NULL, if any arguments are invalid.
282 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
284 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
290 if (!ChrCmpIA(*lpszStr, ch))
291 return (LPSTR)lpszStr;
292 lpszStr = CharNextA(lpszStr);
298 /*************************************************************************
299 * StrChrIW [SHLWAPI.@]
303 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
305 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
312 if (toupperW(*lpszStr) == ch)
313 return (LPWSTR)lpszStr;
318 return (LPWSTR)lpszStr;
321 /*************************************************************************
322 * StrChrNW [SHLWAPI.@]
324 LPWSTR WINAPI StrChrNW(LPCWSTR lpszStr, WCHAR ch, UINT cchMax)
326 TRACE("(%s(%i),%i)\n", debugstr_wn(lpszStr,cchMax), cchMax, ch);
330 while (*lpszStr && cchMax-- > 0)
333 return (LPWSTR)lpszStr;
340 /*************************************************************************
341 * StrCmpIW [SHLWAPI.@]
343 * Compare two strings, ignoring case.
346 * lpszStr [I] First string to compare
347 * lpszComp [I] Second string to compare
350 * An integer less than, equal to or greater than 0, indicating that
351 * lpszStr is less than, the same, or greater than lpszComp.
353 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
357 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
359 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
360 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
363 /*************************************************************************
364 * StrCmpNA [SHLWAPI.@]
366 * Compare two strings, up to a maximum length.
369 * lpszStr [I] First string to compare
370 * lpszComp [I] Second string to compare
371 * iLen [I] Maximum number of chars to compare.
374 * An integer less than, equal to or greater than 0, indicating that
375 * lpszStr is less than, the same, or greater than lpszComp.
377 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
381 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
383 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
384 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
387 /*************************************************************************
388 * StrCmpNW [SHLWAPI.@]
392 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
396 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
398 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
399 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
402 /*************************************************************************
403 * StrCmpNIA [SHLWAPI.@]
405 * Compare two strings, up to a maximum length, ignoring case.
408 * lpszStr [I] First string to compare
409 * lpszComp [I] Second string to compare
410 * iLen [I] Maximum number of chars to compare.
413 * An integer less than, equal to or greater than 0, indicating that
414 * lpszStr is less than, the same, or greater than lpszComp.
416 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
420 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
422 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
423 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
426 /*************************************************************************
427 * StrCmpNIW [SHLWAPI.@]
431 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
435 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
437 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
438 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
441 /*************************************************************************
442 * StrCmpW [SHLWAPI.@]
444 * Compare two strings.
447 * lpszStr [I] First string to compare
448 * lpszComp [I] Second string to compare
451 * An integer less than, equal to or greater than 0, indicating that
452 * lpszStr is less than, the same, or greater than lpszComp.
454 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
458 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
460 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
461 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
464 /*************************************************************************
465 * StrCatW [SHLWAPI.@]
467 * Concatenate two strings.
470 * lpszStr [O] Initial string
471 * lpszSrc [I] String to concatenate
476 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
478 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
480 if (lpszStr && lpszSrc)
481 strcatW(lpszStr, lpszSrc);
485 /*************************************************************************
486 * StrCpyW [SHLWAPI.@]
488 * Copy a string to another string.
491 * lpszStr [O] Destination string
492 * lpszSrc [I] Source string
497 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
499 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
501 if (lpszStr && lpszSrc)
502 strcpyW(lpszStr, lpszSrc);
506 /*************************************************************************
507 * StrCpyNW [SHLWAPI.@]
509 * Copy a string to another string, up to a maximum number of characters.
512 * dst [O] Destination string
513 * src [I] Source string
514 * count [I] Maximum number of chars to copy
519 LPWSTR WINAPI StrCpyNW(LPWSTR dst, LPCWSTR src, int count)
524 TRACE("(%p,%s,%i)\n", dst, debugstr_w(src), count);
528 while ((count > 1) && *s)
539 /*************************************************************************
540 * SHLWAPI_StrStrHelperA
542 * Internal implementation of StrStrA/StrStrIA
544 static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
545 INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT))
549 if (!lpszStr || !lpszSearch || !*lpszSearch)
552 iLen = strlen(lpszSearch);
556 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
557 return (LPSTR)lpszStr;
558 lpszStr = CharNextA(lpszStr);
563 /*************************************************************************
564 * StrStrA [SHLWAPI.@]
566 * Find a substring within a string.
569 * lpszStr [I] String to search in
570 * lpszSearch [I] String to look for
573 * The start of lpszSearch within lpszStr, or NULL if not found.
575 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
577 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
579 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA);
582 /*************************************************************************
583 * StrStrW [SHLWAPI.@]
587 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
589 TRACE("(%s, %s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
591 if (!lpszStr || !lpszSearch || !*lpszSearch) return NULL;
592 return strstrW( lpszStr, lpszSearch );
595 /*************************************************************************
596 * StrRStrIA [SHLWAPI.@]
598 * Find the last occurrence of a substring within a string.
601 * lpszStr [I] String to search in
602 * lpszEnd [I] End of lpszStr
603 * lpszSearch [I] String to look for
606 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
608 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
613 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
615 if (!lpszStr || !lpszSearch || !*lpszSearch)
619 lpszEnd = lpszStr + lstrlenA(lpszStr);
620 if (lpszEnd == lpszStr)
623 if (IsDBCSLeadByte(*lpszSearch))
624 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
627 iLen = lstrlenA(lpszSearch);
631 lpszEnd = CharPrevA(lpszStr, lpszEnd);
632 ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd;
633 if (!ChrCmpIA(ch1, ch2))
635 if (!StrCmpNIA(lpszEnd, lpszSearch, iLen))
636 return (LPSTR)lpszEnd;
638 } while (lpszEnd > lpszStr);
642 /*************************************************************************
643 * StrRStrIW [SHLWAPI.@]
647 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
651 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
653 if (!lpszStr || !lpszSearch || !*lpszSearch)
657 lpszEnd = lpszStr + strlenW(lpszStr);
659 iLen = strlenW(lpszSearch);
661 while (lpszEnd > lpszStr)
664 if (!StrCmpNIW(lpszEnd, lpszSearch, iLen))
665 return (LPWSTR)lpszEnd;
670 /*************************************************************************
671 * StrStrIA [SHLWAPI.@]
673 * Find a substring within a string, ignoring case.
676 * lpszStr [I] String to search in
677 * lpszSearch [I] String to look for
680 * The start of lpszSearch within lpszStr, or NULL if not found.
682 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
684 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
686 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA);
689 /*************************************************************************
690 * StrStrIW [SHLWAPI.@]
694 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
698 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
700 if (!lpszStr || !lpszSearch || !*lpszSearch)
703 iLen = strlenW(lpszSearch);
707 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
708 return (LPWSTR)lpszStr;
714 /*************************************************************************
715 * StrStrNW [SHLWAPI.@]
717 * Find a substring within a string up to a given number of initial characters.
720 * lpFirst [I] String to search in
721 * lpSrch [I] String to look for
722 * cchMax [I] Maximum number of initial search characters
725 * The start of lpFirst within lpSrch, or NULL if not found.
727 LPWSTR WINAPI StrStrNW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
732 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
734 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
737 len = strlenW(lpSrch);
739 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
741 if (!strncmpW(lpFirst, lpSrch, len))
742 return (LPWSTR)lpFirst;
748 /*************************************************************************
749 * StrStrNIW [SHLWAPI.@]
751 * Find a substring within a string up to a given number of initial characters,
755 * lpFirst [I] String to search in
756 * lpSrch [I] String to look for
757 * cchMax [I] Maximum number of initial search characters
760 * The start of lpFirst within lpSrch, or NULL if not found.
762 LPWSTR WINAPI StrStrNIW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
767 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
769 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
772 len = strlenW(lpSrch);
774 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
776 if (!strncmpiW(lpFirst, lpSrch, len))
777 return (LPWSTR)lpFirst;
783 /*************************************************************************
784 * StrToIntA [SHLWAPI.@]
786 * Read a signed integer from a string.
789 * lpszStr [I] String to read integer from
792 * The signed integer value represented by the string, or 0 if no integer is
796 * No leading space is allowed before the number, although a leading '-' is.
798 int WINAPI StrToIntA(LPCSTR lpszStr)
802 TRACE("(%s)\n", debugstr_a(lpszStr));
806 WARN("Invalid lpszStr would crash under Win32!\n");
810 if (*lpszStr == '-' || isdigit(*lpszStr))
811 StrToIntExA(lpszStr, 0, &iRet);
815 /*************************************************************************
816 * StrToIntW [SHLWAPI.@]
820 int WINAPI StrToIntW(LPCWSTR lpszStr)
824 TRACE("(%s)\n", debugstr_w(lpszStr));
828 WARN("Invalid lpszStr would crash under Win32!\n");
832 if (*lpszStr == '-' || isdigitW(*lpszStr))
833 StrToIntExW(lpszStr, 0, &iRet);
837 /*************************************************************************
838 * StrToIntExA [SHLWAPI.@]
840 * Read an integer from a string.
843 * lpszStr [I] String to read integer from
844 * dwFlags [I] Flags controlling the conversion
845 * lpiRet [O] Destination for read integer.
848 * Success: TRUE. lpiRet contains the integer value represented by the string.
849 * Failure: FALSE, if the string is invalid, or no number is present.
852 * Leading whitespace, '-' and '+' are allowed before the number. If
853 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
854 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
855 * the string is treated as a decimal string. A leading '-' is ignored for
856 * hexadecimal numbers.
858 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
863 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
865 bRes = StrToInt64ExA(lpszStr, dwFlags, &li);
866 if (bRes) *lpiRet = li;
870 /*************************************************************************
871 * StrToInt64ExA [SHLWAPI.@]
875 BOOL WINAPI StrToInt64ExA(LPCSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
877 BOOL bNegative = FALSE;
880 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
882 if (!lpszStr || !lpiRet)
884 WARN("Invalid parameter would crash under Win32!\n");
887 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
889 /* Skip leading space, '+', '-' */
890 while (isspace(*lpszStr))
891 lpszStr = CharNextA(lpszStr);
898 else if (*lpszStr == '+')
901 if (dwFlags & STIF_SUPPORT_HEX &&
902 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
904 /* Read hex number */
907 if (!isxdigit(*lpszStr))
910 while (isxdigit(*lpszStr))
913 if (isdigit(*lpszStr))
914 iRet += (*lpszStr - '0');
916 iRet += 10 + (tolower(*lpszStr) - 'a');
923 /* Read decimal number */
924 if (!isdigit(*lpszStr))
927 while (isdigit(*lpszStr))
930 iRet += (*lpszStr - '0');
933 *lpiRet = bNegative ? -iRet : iRet;
937 /*************************************************************************
938 * StrToIntExW [SHLWAPI.@]
942 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
947 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
949 bRes = StrToInt64ExW(lpszStr, dwFlags, &li);
950 if (bRes) *lpiRet = li;
954 /*************************************************************************
955 * StrToInt64ExW [SHLWAPI.@]
959 BOOL WINAPI StrToInt64ExW(LPCWSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
961 BOOL bNegative = FALSE;
964 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
966 if (!lpszStr || !lpiRet)
968 WARN("Invalid parameter would crash under Win32!\n");
971 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
973 /* Skip leading space, '+', '-' */
974 while (isspaceW(*lpszStr)) lpszStr++;
981 else if (*lpszStr == '+')
984 if (dwFlags & STIF_SUPPORT_HEX &&
985 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
987 /* Read hex number */
990 if (!isxdigitW(*lpszStr))
993 while (isxdigitW(*lpszStr))
996 if (isdigitW(*lpszStr))
997 iRet += (*lpszStr - '0');
999 iRet += 10 + (tolowerW(*lpszStr) - 'a');
1006 /* Read decimal number */
1007 if (!isdigitW(*lpszStr))
1010 while (isdigitW(*lpszStr))
1013 iRet += (*lpszStr - '0');
1016 *lpiRet = bNegative ? -iRet : iRet;
1020 /*************************************************************************
1021 * StrDupA [SHLWAPI.@]
1023 * Duplicate a string.
1026 * lpszStr [I] String to duplicate.
1029 * Success: A pointer to a new string containing the contents of lpszStr
1030 * Failure: NULL, if memory cannot be allocated
1033 * The string memory is allocated with LocalAlloc(), and so should be released
1034 * by calling LocalFree().
1036 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
1041 TRACE("(%s)\n",debugstr_a(lpszStr));
1043 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
1044 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1049 memcpy(lpszRet, lpszStr, iLen);
1056 /*************************************************************************
1057 * StrDupW [SHLWAPI.@]
1061 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
1066 TRACE("(%s)\n",debugstr_w(lpszStr));
1068 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
1069 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1074 memcpy(lpszRet, lpszStr, iLen);
1081 /*************************************************************************
1082 * SHLWAPI_StrSpnHelperA
1084 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1086 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
1087 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
1090 LPCSTR lpszRead = lpszStr;
1091 if (lpszStr && *lpszStr && lpszMatch)
1095 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1097 if (!bInvert && !lpszTest)
1099 if (bInvert && lpszTest)
1101 lpszRead = CharNextA(lpszRead);
1104 return lpszRead - lpszStr;
1107 /*************************************************************************
1108 * StrSpnA [SHLWAPI.@]
1110 * Find the length of the start of a string that contains only certain
1114 * lpszStr [I] String to search
1115 * lpszMatch [I] Characters that can be in the substring
1118 * The length of the part of lpszStr containing only chars from lpszMatch,
1119 * or 0 if any parameter is invalid.
1121 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1123 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1125 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1128 /*************************************************************************
1129 * StrSpnW [SHLWAPI.@]
1133 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1135 if (!lpszStr || !lpszMatch) return 0;
1136 return strspnW( lpszStr, lpszMatch );
1139 /*************************************************************************
1140 * StrCSpnA [SHLWAPI.@]
1142 * Find the length of the start of a string that does not contain certain
1146 * lpszStr [I] String to search
1147 * lpszMatch [I] Characters that cannot be in the substring
1150 * The length of the part of lpszStr containing only chars not in lpszMatch,
1151 * or 0 if any parameter is invalid.
1153 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1155 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1157 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1160 /*************************************************************************
1161 * StrCSpnW [SHLWAPI.@]
1165 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1167 if (!lpszStr || !lpszMatch) return 0;
1168 return strcspnW( lpszStr, lpszMatch );
1171 /*************************************************************************
1172 * StrCSpnIA [SHLWAPI.@]
1174 * Find the length of the start of a string that does not contain certain
1175 * characters, ignoring case.
1178 * lpszStr [I] String to search
1179 * lpszMatch [I] Characters that cannot be in the substring
1182 * The length of the part of lpszStr containing only chars not in lpszMatch,
1183 * or 0 if any parameter is invalid.
1185 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1187 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1189 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1192 /*************************************************************************
1193 * StrCSpnIW [SHLWAPI.@]
1197 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1199 LPCWSTR lpszRead = lpszStr;
1201 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1203 if (lpszStr && *lpszStr && lpszMatch)
1207 if (StrChrIW(lpszMatch, *lpszRead)) break;
1211 return lpszRead - lpszStr;
1214 /*************************************************************************
1215 * StrPBrkA [SHLWAPI.@]
1217 * Search a string for any of a group of characters.
1220 * lpszStr [I] String to search
1221 * lpszMatch [I] Characters to match
1224 * A pointer to the first matching character in lpszStr, or NULL if no
1227 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1229 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1231 if (lpszStr && lpszMatch && *lpszMatch)
1235 if (StrChrA(lpszMatch, *lpszStr))
1236 return (LPSTR)lpszStr;
1237 lpszStr = CharNextA(lpszStr);
1243 /*************************************************************************
1244 * StrPBrkW [SHLWAPI.@]
1248 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1250 if (!lpszStr || !lpszMatch) return NULL;
1251 return strpbrkW( lpszStr, lpszMatch );
1254 /*************************************************************************
1255 * SHLWAPI_StrRChrHelperA
1257 * Internal implementation of StrRChrA/StrRChrIA.
1259 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1260 LPCSTR lpszEnd, WORD ch,
1261 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1263 LPCSTR lpszRet = NULL;
1270 lpszEnd = lpszStr + lstrlenA(lpszStr);
1272 while (*lpszStr && lpszStr <= lpszEnd)
1274 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1276 if (!pChrCmpFn(ch, ch2))
1278 lpszStr = CharNextA(lpszStr);
1281 return (LPSTR)lpszRet;
1284 /**************************************************************************
1285 * StrRChrA [SHLWAPI.@]
1287 * Find the last occurrence of a character in string.
1290 * lpszStr [I] String to search in
1291 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1292 * ch [I] Character to search for.
1295 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1296 * or NULL if not found.
1297 * Failure: NULL, if any arguments are invalid.
1299 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1301 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1303 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1306 /**************************************************************************
1307 * StrRChrW [SHLWAPI.@]
1311 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
1315 if (!str) return NULL;
1316 if (!end) end = str + strlenW(str);
1319 if (*str == ch) ret = (WCHAR *)str;
1325 /**************************************************************************
1326 * StrRChrIA [SHLWAPI.@]
1328 * Find the last occurrence of a character in string, ignoring case.
1331 * lpszStr [I] String to search in
1332 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1333 * ch [I] Character to search for.
1336 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1337 * or NULL if not found.
1338 * Failure: NULL, if any arguments are invalid.
1340 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1342 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1344 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1347 /**************************************************************************
1348 * StrRChrIW [SHLWAPI.@]
1352 LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch)
1356 if (!str) return NULL;
1357 if (!end) end = str + strlenW(str);
1360 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
1366 /*************************************************************************
1367 * StrCatBuffA [SHLWAPI.@]
1369 * Concatenate two strings together.
1372 * lpszStr [O] String to concatenate to
1373 * lpszCat [I] String to add to lpszCat
1374 * cchMax [I] Maximum number of characters for the whole string
1380 * cchMax determines the number of characters in the final length of the
1381 * string, not the number appended to lpszStr from lpszCat.
1383 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1387 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1391 WARN("Invalid lpszStr would crash under Win32!\n");
1395 iLen = strlen(lpszStr);
1399 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1403 /*************************************************************************
1404 * StrCatBuffW [SHLWAPI.@]
1408 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1412 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1416 WARN("Invalid lpszStr would crash under Win32!\n");
1420 iLen = strlenW(lpszStr);
1424 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1428 /*************************************************************************
1429 * StrRetToBufA [SHLWAPI.@]
1431 * Convert a STRRET to a normal string.
1434 * lpStrRet [O] STRRET to convert
1435 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1436 * lpszDest [O] Destination for normal string
1437 * dwLen [I] Length of lpszDest
1440 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1441 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1442 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1443 * Failure: E_FAIL, if any parameters are invalid.
1445 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1448 * This routine is identical to that in dlls/shell32/shellstring.c.
1449 * It was duplicated because not every version of Shlwapi.dll exports
1450 * StrRetToBufA. If you change one routine, change them both.
1452 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1456 WARN("Invalid lpStrRet would crash under Win32!\n");
1470 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1471 CoTaskMemFree(src->u.pOleStr);
1475 lstrcpynA(dest, src->u.cStr, len);
1479 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1483 FIXME("unknown type!\n");
1489 /*************************************************************************
1490 * StrRetToBufW [SHLWAPI.@]
1494 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1496 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1500 WARN("Invalid lpStrRet would crash under Win32!\n");
1514 lstrcpynW(dest, src->u.pOleStr, len);
1515 CoTaskMemFree(src->u.pOleStr);
1519 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ))
1526 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1533 FIXME("unknown type!\n");
1539 /*************************************************************************
1540 * StrRetToStrA [SHLWAPI.@]
1542 * Converts a STRRET to a normal string.
1545 * lpStrRet [O] STRRET to convert
1546 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1547 * ppszName [O] Destination for converted string
1550 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1551 * Failure: E_FAIL, if any parameters are invalid.
1553 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1555 HRESULT hRet = E_FAIL;
1557 switch (lpStrRet->uType)
1560 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1561 CoTaskMemFree(lpStrRet->u.pOleStr);
1565 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1569 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1579 /*************************************************************************
1580 * StrRetToStrW [SHLWAPI.@]
1584 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1586 HRESULT hRet = E_FAIL;
1588 switch (lpStrRet->uType)
1591 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1592 CoTaskMemFree(lpStrRet->u.pOleStr);
1596 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1600 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1610 /* Create an ASCII string copy using SysAllocString() */
1611 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1617 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1618 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1622 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1623 *pBstrOut = SysAllocString(szTemp);
1624 HeapFree(GetProcessHeap(), 0, szTemp);
1630 return E_OUTOFMEMORY;
1633 /*************************************************************************
1634 * StrRetToBSTR [SHLWAPI.@]
1636 * Converts a STRRET to a BSTR.
1639 * lpStrRet [O] STRRET to convert
1640 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1641 * pBstrOut [O] Destination for converted BSTR
1644 * Success: S_OK. pBstrOut contains the new string.
1645 * Failure: E_FAIL, if any parameters are invalid.
1647 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1649 HRESULT hRet = E_FAIL;
1651 switch (lpStrRet->uType)
1654 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1657 CoTaskMemFree(lpStrRet->u.pOleStr);
1661 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1665 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1675 /*************************************************************************
1676 * StrFormatKBSizeA [SHLWAPI.@]
1678 * Create a formatted string containing a byte count in Kilobytes.
1681 * llBytes [I] Byte size to format
1682 * lpszDest [I] Destination for formatted string
1683 * cchMax [I] Size of lpszDest
1688 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1692 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1694 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1699 /*************************************************************************
1700 * StrFormatKBSizeW [SHLWAPI.@]
1702 * See StrFormatKBSizeA.
1704 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1706 static const WCHAR kb[] = {' ','K','B',0};
1707 LONGLONG llKB = (llBytes + 1023) >> 10;
1710 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1712 if (!FormatInt(llKB, lpszDest, cchMax))
1715 len = lstrlenW(lpszDest);
1716 if (cchMax - len < 4)
1718 lstrcatW(lpszDest, kb);
1722 /*************************************************************************
1723 * StrNCatA [SHLWAPI.@]
1725 * Concatenate two strings together.
1728 * lpszStr [O] String to concatenate to
1729 * lpszCat [I] String to add to lpszCat
1730 * cchMax [I] Maximum number of characters to concatenate
1736 * cchMax determines the number of characters that are appended to lpszStr,
1737 * not the total length of the string.
1739 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1741 LPSTR lpszRet = lpszStr;
1743 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1747 WARN("Invalid lpszStr would crash under Win32!\n");
1751 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1755 /*************************************************************************
1756 * StrNCatW [SHLWAPI.@]
1760 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1762 LPWSTR lpszRet = lpszStr;
1764 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1768 WARN("Invalid lpszStr would crash under Win32\n");
1772 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1776 /*************************************************************************
1777 * StrTrimA [SHLWAPI.@]
1779 * Remove characters from the start and end of a string.
1782 * lpszStr [O] String to remove characters from
1783 * lpszTrim [I] Characters to remove from lpszStr
1786 * TRUE If lpszStr was valid and modified
1789 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1792 LPSTR lpszRead = lpszStr;
1795 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1797 if (lpszRead && *lpszRead)
1799 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1800 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1802 dwLen = strlen(lpszRead);
1804 if (lpszRead != lpszStr)
1806 memmove(lpszStr, lpszRead, dwLen + 1);
1811 lpszRead = lpszStr + dwLen;
1812 while (StrChrA(lpszTrim, lpszRead[-1]))
1813 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1815 if (lpszRead != lpszStr + dwLen)
1825 /*************************************************************************
1826 * StrTrimW [SHLWAPI.@]
1830 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1833 LPWSTR lpszRead = lpszStr;
1836 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1838 if (lpszRead && *lpszRead)
1840 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++;
1842 dwLen = strlenW(lpszRead);
1844 if (lpszRead != lpszStr)
1846 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1851 lpszRead = lpszStr + dwLen;
1852 while (StrChrW(lpszTrim, lpszRead[-1]))
1853 lpszRead--; /* Skip trailing matches */
1855 if (lpszRead != lpszStr + dwLen)
1865 /*************************************************************************
1866 * _SHStrDupAA [INTERNAL]
1868 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1870 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest)
1876 len = lstrlenA(src) + 1;
1877 *dest = CoTaskMemAlloc(len);
1883 lstrcpynA(*dest,src, len);
1889 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1893 /*************************************************************************
1894 * SHStrDupA [SHLWAPI.@]
1896 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1899 * lpszStr [I] String to copy
1900 * lppszDest [O] Destination for the new string copy
1903 * Success: S_OK. lppszDest contains the new string in Unicode format.
1904 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1907 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1914 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1915 *lppszDest = CoTaskMemAlloc(len);
1922 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1926 hRet = E_OUTOFMEMORY;
1928 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1932 /*************************************************************************
1933 * _SHStrDupAW [INTERNAL]
1935 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1937 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1943 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1944 *dest = CoTaskMemAlloc(len);
1950 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1956 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1960 /*************************************************************************
1961 * SHStrDupW [SHLWAPI.@]
1965 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1971 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1972 *dest = CoTaskMemAlloc(len);
1978 memcpy(*dest, src, len);
1984 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1988 /*************************************************************************
1989 * SHLWAPI_WriteReverseNum
1991 * Internal helper for SHLWAPI_WriteTimeClass.
1993 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1997 /* Write a decimal number to a string, backwards */
2000 DWORD dwNextDigit = dwNum % 10;
2001 *lpszOut-- = '0' + dwNextDigit;
2002 dwNum = (dwNum - dwNextDigit) / 10;
2003 } while (dwNum > 0);
2008 /*************************************************************************
2009 * SHLWAPI_FormatSignificant
2011 * Internal helper for SHLWAPI_WriteTimeClass.
2013 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
2015 /* Zero non significant digits, return remaining significant digits */
2019 if (--dwDigits == 0)
2029 /*************************************************************************
2030 * SHLWAPI_WriteTimeClass
2032 * Internal helper for StrFromTimeIntervalW.
2034 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
2035 UINT uClassStringId, int iDigits)
2037 WCHAR szBuff[64], *szOut = szBuff + 32;
2039 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
2040 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
2042 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
2043 strcatW(lpszOut, szOut);
2047 /*************************************************************************
2048 * StrFromTimeIntervalA [SHLWAPI.@]
2050 * Format a millisecond time interval into a string
2053 * lpszStr [O] Output buffer for formatted time interval
2054 * cchMax [I] Size of lpszStr
2055 * dwMS [I] Number of milliseconds
2056 * iDigits [I] Number of digits to print
2059 * The length of the formatted string, or 0 if any parameter is invalid.
2062 * This implementation mimics the Win32 behaviour of always writing a leading
2063 * space before the time interval begins.
2065 * iDigits is used to provide approximate times if accuracy is not important.
2066 * This number of digits will be written of the first non-zero time class
2067 * (hours/minutes/seconds). If this does not complete the time classification,
2068 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2069 * If there are digits remaining following the writing of a time class, the
2070 * next time class will be written.
2072 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2073 * following will result from the given values of iDigits:
2075 *| iDigits 1 2 3 4 5 ...
2076 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2078 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
2083 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2085 if (lpszStr && cchMax)
2088 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
2089 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2095 /*************************************************************************
2096 * StrFromTimeIntervalW [SHLWAPI.@]
2098 * See StrFromTimeIntervalA.
2100 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2105 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2107 if (lpszStr && cchMax)
2110 DWORD dwHours, dwMinutes;
2112 if (!iDigits || cchMax == 1)
2118 /* Calculate the time classes */
2119 dwMS = (dwMS + 500) / 1000;
2120 dwHours = dwMS / 3600;
2121 dwMS -= dwHours * 3600;
2122 dwMinutes = dwMS / 60;
2123 dwMS -= dwMinutes * 60;
2128 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2130 if (dwMinutes && iDigits)
2131 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2133 if (iDigits) /* Always write seconds if we have significant digits */
2134 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2136 lstrcpynW(lpszStr, szCopy, cchMax);
2137 iRet = strlenW(lpszStr);
2142 /*************************************************************************
2143 * StrIsIntlEqualA [SHLWAPI.@]
2145 * Compare two strings.
2148 * bCase [I] Whether to compare case sensitively
2149 * lpszStr [I] First string to compare
2150 * lpszComp [I] Second string to compare
2151 * iLen [I] Length to compare
2154 * TRUE If the strings are equal.
2157 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2162 TRACE("(%d,%s,%s,%d)\n", bCase,
2163 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2165 /* FIXME: This flag is undocumented and unknown by our CompareString.
2166 * We need a define for it.
2168 dwFlags = 0x10000000;
2169 if (!bCase) dwFlags |= NORM_IGNORECASE;
2171 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2174 /*************************************************************************
2175 * StrIsIntlEqualW [SHLWAPI.@]
2177 * See StrIsIntlEqualA.
2179 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2184 TRACE("(%d,%s,%s,%d)\n", bCase,
2185 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2187 /* FIXME: This flag is undocumented and unknown by our CompareString.
2188 * We need a define for it.
2190 dwFlags = 0x10000000;
2191 if (!bCase) dwFlags |= NORM_IGNORECASE;
2193 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2196 /*************************************************************************
2199 * Copy a string to another string, up to a maximum number of characters.
2202 * lpszDest [O] Destination string
2203 * lpszSrc [I] Source string
2204 * iLen [I] Maximum number of chars to copy
2207 * Success: A pointer to the last character written to lpszDest.
2208 * Failure: lpszDest, if any arguments are invalid.
2210 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2212 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2214 if (lpszDest && lpszSrc && iLen > 0)
2216 while ((iLen-- > 1) && *lpszSrc)
2217 *lpszDest++ = *lpszSrc++;
2224 /*************************************************************************
2227 * Unicode version of StrCpyNXA.
2229 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2231 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2233 if (lpszDest && lpszSrc && iLen > 0)
2235 while ((iLen-- > 1) && *lpszSrc)
2236 *lpszDest++ = *lpszSrc++;
2243 /*************************************************************************
2244 * StrCmpLogicalW [SHLWAPI.@]
2246 * Compare two strings, ignoring case and comparing digits as numbers.
2249 * lpszStr [I] First string to compare
2250 * lpszComp [I] Second string to compare
2251 * iLen [I] Length to compare
2254 * TRUE If the strings are equal.
2257 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2261 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2263 if (lpszStr && lpszComp)
2269 else if (isdigitW(*lpszStr))
2273 if (!isdigitW(*lpszComp))
2276 /* Compare the numbers */
2277 StrToIntExW(lpszStr, 0, &iStr);
2278 StrToIntExW(lpszComp, 0, &iComp);
2282 else if (iStr > iComp)
2286 while (isdigitW(*lpszStr))
2288 while (isdigitW(*lpszComp))
2291 else if (isdigitW(*lpszComp))
2295 iDiff = ChrCmpIW(*lpszStr,*lpszComp);
2311 /* Structure for formatting byte strings */
2312 typedef struct tagSHLWAPI_BYTEFORMATS
2319 } SHLWAPI_BYTEFORMATS;
2321 /*************************************************************************
2322 * StrFormatByteSizeW [SHLWAPI.@]
2324 * Create a string containing an abbreviated byte count of up to 2^63-1.
2327 * llBytes [I] Byte size to format
2328 * lpszDest [I] Destination for formatted string
2329 * cchMax [I] Size of lpszDest
2335 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2337 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2339 #define KB ((ULONGLONG)1024)
2341 #define GB (KB*KB*KB)
2342 #define TB (KB*KB*KB*KB)
2343 #define PB (KB*KB*KB*KB*KB)
2345 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2347 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2348 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2349 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2350 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2351 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2352 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2353 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2354 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2355 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2356 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2357 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2358 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2359 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2360 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2361 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2362 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2364 WCHAR wszAdd[] = {' ','?','B',0};
2368 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2370 if (!lpszDest || !cchMax)
2373 if (llBytes < 1024) /* 1K */
2375 WCHAR wszBytesFormat[64];
2376 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2377 snprintfW(lpszDest, cchMax, wszBytesFormat, (int)llBytes);
2381 /* Note that if this loop completes without finding a match, i will be
2382 * pointing at the last entry, which is a catch all for > 1000 PB
2384 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2386 if (llBytes < bfFormats[i].dLimit)
2390 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2391 * this number we integer shift down by 1 MB first. The table above has
2392 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2393 * for this. We also add a small fudge factor to get the correct result for
2394 * counts that lie exactly on a 1024 byte boundary.
2397 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by 1 MB */
2399 dBytes = (double)llBytes + 0.00001;
2401 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2403 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2405 wszAdd[1] = bfFormats[i].wPrefix;
2406 StrCatBuffW(lpszDest, wszAdd, cchMax);
2410 /*************************************************************************
2411 * StrFormatByteSize64A [SHLWAPI.@]
2413 * See StrFormatByteSizeW.
2415 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2419 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2422 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2426 /*************************************************************************
2427 * StrFormatByteSizeA [SHLWAPI.@]
2429 * Create a string containing an abbreviated byte count of up to 2^31-1.
2432 * dwBytes [I] Byte size to format
2433 * lpszDest [I] Destination for formatted string
2434 * cchMax [I] Size of lpszDest
2440 * The Ascii and Unicode versions of this function accept a different
2441 * integer type for dwBytes. See StrFormatByteSize64A().
2443 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2445 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2447 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2450 /*************************************************************************
2453 * Remove a hanging lead byte from the end of a string, if present.
2456 * lpStr [I] String to check for a hanging lead byte
2457 * size [I] Length of lpStr
2460 * Success: The new length of the string. Any hanging lead bytes are removed.
2461 * Failure: 0, if any parameters are invalid.
2463 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2467 LPSTR lastByte = lpStr + size - 1;
2469 while(lpStr < lastByte)
2470 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2472 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2482 /*************************************************************************
2485 * Remove a single non-trailing ampersand ('&') from a string.
2488 * lpszStr [I/O] String to remove ampersand from.
2491 * The character after the first ampersand in lpszStr, or the first character
2492 * in lpszStr if there is no ampersand in the string.
2494 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2496 LPSTR lpszIter, lpszTmp;
2499 TRACE("(%s)\n", debugstr_a(lpszStr));
2503 if ((lpszIter = StrChrA(lpszStr, '&')))
2505 lpszTmp = CharNextA(lpszIter);
2508 if (*lpszTmp != '&')
2511 memmove( lpszIter, lpszTmp, strlen(lpszTmp) + 1 );
2518 /*************************************************************************
2521 * Unicode version of SHStripMneumonicA.
2523 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2525 LPWSTR lpszIter, lpszTmp;
2528 TRACE("(%s)\n", debugstr_w(lpszStr));
2532 if ((lpszIter = StrChrW(lpszStr, '&')))
2534 lpszTmp = lpszIter + 1;
2537 if (*lpszTmp != '&')
2540 memmove( lpszIter, lpszTmp, (strlenW(lpszTmp) + 1) * sizeof(WCHAR) );
2547 /*************************************************************************
2550 * Convert an Ascii string to Unicode.
2553 * dwCp [I] Code page for the conversion
2554 * lpSrcStr [I] Source Ascii string to convert
2555 * lpDstStr [O] Destination for converted Unicode string
2556 * iLen [I] Length of lpDstStr
2559 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2561 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2565 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2566 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2570 /*************************************************************************
2573 * Convert an Ascii string to Unicode.
2576 * lpSrcStr [I] Source Ascii string to convert
2577 * lpDstStr [O] Destination for converted Unicode string
2578 * iLen [I] Length of lpDstStr
2581 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2584 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2586 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2588 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2591 /*************************************************************************
2594 * Convert a Unicode string to Ascii.
2597 * CodePage [I] Code page to use for the conversion
2598 * lpSrcStr [I] Source Unicode string to convert
2599 * lpDstStr [O] Destination for converted Ascii string
2600 * dstlen [I] Length of buffer at lpDstStr
2603 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2604 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2605 * the result is not nul-terminated.
2606 * When using a different codepage, the length in bytes of the truncated
2607 * result at lpDstStr (including the terminator) is returned and
2608 * lpDstStr is always nul-terminated.
2611 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen)
2613 static const WCHAR emptyW[] = { '\0' };
2617 if (!lpDstStr || !dstlen)
2625 len = strlenW(lpSrcStr) + 1;
2630 CodePage = CP_UTF8; /* Fall through... */
2631 case 0x0000C350: /* FIXME: CP_ #define */
2637 INT needed = dstlen - 1;
2640 /* try the user supplied buffer first */
2641 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed);
2644 lpDstStr[needed] = '\0';
2648 /* user buffer too small. exclude termination and copy as much as possible */
2650 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed);
2652 mem = HeapAlloc(GetProcessHeap(), 0, needed);
2656 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed);
2659 reqLen = SHTruncateString(mem, dstlen);
2660 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1);
2662 HeapFree(GetProcessHeap(), 0, mem);
2669 /* try the user supplied buffer first */
2670 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL);
2672 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2674 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2677 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2680 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2681 reqLen, NULL, NULL);
2683 reqLen = SHTruncateString(mem, dstlen -1);
2686 lstrcpynA(lpDstStr, mem, reqLen);
2687 HeapFree(GetProcessHeap(), 0, mem);
2688 lpDstStr[reqLen-1] = '\0';
2695 /*************************************************************************
2698 * Convert a Unicode string to Ascii.
2701 * lpSrcStr [I] Source Unicode string to convert
2702 * lpDstStr [O] Destination for converted Ascii string
2703 * iLen [O] Length of lpDstStr in characters
2706 * See SHUnicodeToAnsiCP
2709 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2711 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2713 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2716 /*************************************************************************
2719 * Copy one string to another.
2722 * lpszSrc [I] Source string to copy
2723 * lpszDst [O] Destination for copy
2724 * iLen [I] Length of lpszDst in characters
2727 * The length of the copied string, including the terminating NUL. lpszDst
2728 * contains iLen characters of lpszSrc.
2730 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2734 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2736 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2737 return lpszRet - lpszDst + 1;
2740 /*************************************************************************
2743 * Unicode version of SSHAnsiToAnsi.
2745 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2749 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2751 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2752 return lpszRet - lpszDst + 1;
2755 /*************************************************************************
2758 * Determine if an Ascii string converts to Unicode and back identically.
2761 * lpSrcStr [I] Source Unicode string to convert
2762 * lpDst [O] Destination for resulting Ascii string
2763 * iLen [I] Length of lpDst in characters
2766 * TRUE, since Ascii strings always convert identically.
2768 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2770 lstrcpynA(lpDst, lpSrcStr, iLen);
2774 /*************************************************************************
2777 * Determine if a Unicode string converts to Ascii and back identically.
2780 * lpSrcStr [I] Source Unicode string to convert
2781 * lpDst [O] Destination for resulting Ascii string
2782 * iLen [I] Length of lpDst in characters
2785 * TRUE, if lpSrcStr converts to Ascii and back identically,
2788 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2790 WCHAR szBuff[MAX_PATH];
2792 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2793 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2794 return !strcmpW(lpSrcStr, szBuff);
2797 /*************************************************************************
2798 * SHLoadIndirectString [SHLWAPI.@]
2800 * If passed a string that begins with '@', extract the string from the
2801 * appropriate resource, otherwise do a straight copy.
2804 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2806 WCHAR *dllname = NULL;
2807 HMODULE hmod = NULL;
2808 HRESULT hr = E_FAIL;
2810 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2818 dllname = StrDupW(src + 1);
2819 index_str = strchrW(dllname, ',');
2821 if(!index_str) goto end;
2825 index = atoiW(index_str);
2827 hmod = LoadLibraryW(dllname);
2832 if(LoadStringW(hmod, -index, dst, dst_len))
2836 FIXME("can't handle non-negative indices (%d)\n", index);
2841 lstrcpynW(dst, src, dst_len);
2845 TRACE("returning %s\n", debugstr_w(dst));
2847 if(hmod) FreeLibrary(hmod);
2848 HeapFree(GetProcessHeap(), 0, dllname);