From 91ec8e14c67e372b5b8bd2d171411dee308d60e2 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 20 Sep 2002 19:41:08 +0000 Subject: [PATCH] Reorganise/minor tidyup of ordinal functions. Implement StrCmpLogicalW,StrFormatByteSizeA/W,StrFormatByteSize64A, SHCreateStreamWrapper. Fix some output .spec parameters from str to ptr. Fix definition of StrFormatByteSize functions. --- dlls/shlwapi/ordinal.c | 250 ++------------------------------------ dlls/shlwapi/path.c | 164 ++++++++++++------------- dlls/shlwapi/regstream.c | 40 ++++++ dlls/shlwapi/shlwapi.spec | 13 +- dlls/shlwapi/string.c | 244 +++++++++++++++++++++++++++++++------ dlls/shlwapi/thread.c | 16 ++- dlls/shlwapi/url.c | 230 ++++++++++++++++++++++++++++++++++- include/shlwapi.h | 13 +- 8 files changed, 602 insertions(+), 368 deletions(-) diff --git a/dlls/shlwapi/ordinal.c b/dlls/shlwapi/ordinal.c index 3c9b148e16b..3a2a7b35460 100644 --- a/dlls/shlwapi/ordinal.c +++ b/dlls/shlwapi/ordinal.c @@ -46,12 +46,21 @@ #include "winreg.h" #include "winuser.h" #include "wine/debug.h" -#include "ordinal.h" #include "shlwapi.h" WINE_DEFAULT_DEBUG_CHANNEL(shell); +/* Get a function pointer from a DLL handle */ +#define GET_FUNC(func, module, name, fail) \ + do { \ + if (!func) { \ + if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \ + if (!(func = (void*)GetProcAddress(SHLWAPI_h##module, name))) return fail; \ + } \ + } while (0) + +/* DLL handles for late bound calls */ extern HINSTANCE shlwapi_hInstance; extern HMODULE SHLWAPI_hshell32; extern HMODULE SHLWAPI_hwinmm; @@ -70,61 +79,7 @@ static DWORD id1[4] = {0xfc4801a3, 0x11cf2ba9, 0xaa0029a2, 0x52733d00}; /* following is GUID for IPersistMoniker::GetClassID -- see _174 */ static DWORD id2[4] = {0x79eac9ee, 0x11cebaf9, 0xaa00828c, 0x0ba94b00}; -/* The following schemes were identified in the native version of - * SHLWAPI.DLL version 5.50 - */ -typedef enum { - URL_SCHEME_INVALID = -1, - URL_SCHEME_UNKNOWN = 0, - URL_SCHEME_FTP, - URL_SCHEME_HTTP, - URL_SCHEME_GOPHER, - URL_SCHEME_MAILTO, - URL_SCHEME_NEWS, - URL_SCHEME_NNTP, - URL_SCHEME_TELNET, - URL_SCHEME_WAIS, - URL_SCHEME_FILE, - URL_SCHEME_MK, - URL_SCHEME_HTTPS, - URL_SCHEME_SHELL, - URL_SCHEME_SNEWS, - URL_SCHEME_LOCAL, - URL_SCHEME_JAVASCRIPT, - URL_SCHEME_VBSCRIPT, - URL_SCHEME_ABOUT, - URL_SCHEME_RES, - URL_SCHEME_MAXVALUE -} URL_SCHEME; - -typedef struct { - URL_SCHEME scheme_number; - LPCSTR scheme_name; -} SHL_2_inet_scheme; - -static const SHL_2_inet_scheme shlwapi_schemes[] = { - {URL_SCHEME_FTP, "ftp"}, - {URL_SCHEME_HTTP, "http"}, - {URL_SCHEME_GOPHER, "gopher"}, - {URL_SCHEME_MAILTO, "mailto"}, - {URL_SCHEME_NEWS, "news"}, - {URL_SCHEME_NNTP, "nntp"}, - {URL_SCHEME_TELNET, "telnet"}, - {URL_SCHEME_WAIS, "wais"}, - {URL_SCHEME_FILE, "file"}, - {URL_SCHEME_MK, "mk"}, - {URL_SCHEME_HTTPS, "https"}, - {URL_SCHEME_SHELL, "shell"}, - {URL_SCHEME_SNEWS, "snews"}, - {URL_SCHEME_LOCAL, "local"}, - {URL_SCHEME_JAVASCRIPT, "javascript"}, - {URL_SCHEME_VBSCRIPT, "vbscript"}, - {URL_SCHEME_ABOUT, "about"}, - {URL_SCHEME_RES, "res"}, - {0, 0} -}; - -/* function pointers for GET_FUNC macro; these need to be global because of gcc bug */ +/* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */ static LPITEMIDLIST (WINAPI *pSHBrowseForFolderW)(LPBROWSEINFOW); static HRESULT (WINAPI *pConvertINetUnicodeToMultiByte)(LPDWORD,DWORD,LPCWSTR,LPINT,LPSTR,LPINT); static BOOL (WINAPI *pPlaySoundW)(LPCWSTR, HMODULE, DWORD); @@ -159,189 +114,6 @@ static HRESULT (WINAPI *pDllGetVersion)(DLLVERSIONINFO*); and recommend the builtin rather than reimplementing the calls here! */ -/************************************************************************* - * @ [SHLWAPI.1] - * - * Identifies the Internet "scheme" in the passed string. ASCII based. - * Also determines start and length of item after the ':' - */ -DWORD WINAPI SHLWAPI_1 (LPCSTR x, UNKNOWN_SHLWAPI_1 *y) -{ - DWORD cnt; - const SHL_2_inet_scheme *inet_pro; - - y->fcncde = URL_SCHEME_INVALID; - if (y->size != 0x18) return E_INVALIDARG; - /* FIXME: leading white space generates error of 0x80041001 which - * is undefined - */ - if (*x <= ' ') return 0x80041001; - cnt = 0; - y->sizep1 = 0; - y->ap1 = x; - while (*x) { - if (*x == ':') { - y->sizep1 = cnt; - cnt = -1; - y->ap2 = x+1; - break; - } - x++; - cnt++; - } - - /* check for no scheme in string start */ - /* (apparently schemes *must* be larger than a single character) */ - if ((*x == '\0') || (y->sizep1 <= 1)) { - y->ap1 = 0; - return 0x80041001; - } - - /* found scheme, set length of remainder */ - y->sizep2 = lstrlenA(y->ap2); - - /* see if known scheme and return indicator number */ - y->fcncde = URL_SCHEME_UNKNOWN; - inet_pro = shlwapi_schemes; - while (inet_pro->scheme_name) { - if (!strncasecmp(inet_pro->scheme_name, y->ap1, - min(y->sizep1, lstrlenA(inet_pro->scheme_name)))) { - y->fcncde = inet_pro->scheme_number; - break; - } - inet_pro++; - } - return S_OK; -} - -/************************************************************************* - * @ [SHLWAPI.2] - * - * Identifies the Internet "scheme" in the passed string. UNICODE based. - * Also determines start and length of item after the ':' - */ -DWORD WINAPI SHLWAPI_2 (LPCWSTR x, UNKNOWN_SHLWAPI_2 *y) -{ - DWORD cnt; - const SHL_2_inet_scheme *inet_pro; - LPSTR cmpstr; - INT len; - - y->fcncde = URL_SCHEME_INVALID; - if (y->size != 0x18) return E_INVALIDARG; - /* FIXME: leading white space generates error of 0x80041001 which - * is undefined - */ - if (*x <= L' ') return 0x80041001; - cnt = 0; - y->sizep1 = 0; - y->ap1 = x; - while (*x) { - if (*x == L':') { - y->sizep1 = cnt; - cnt = -1; - y->ap2 = x+1; - break; - } - x++; - cnt++; - } - - /* check for no scheme in string start */ - /* (apparently schemes *must* be larger than a single character) */ - if ((*x == L'\0') || (y->sizep1 <= 1)) { - y->ap1 = 0; - return 0x80041001; - } - - /* found scheme, set length of remainder */ - y->sizep2 = lstrlenW(y->ap2); - - /* see if known scheme and return indicator number */ - len = WideCharToMultiByte(0, 0, y->ap1, y->sizep1, 0, 0, 0, 0); - cmpstr = (LPSTR)HeapAlloc(GetProcessHeap(), 0, len+1); - WideCharToMultiByte(0, 0, y->ap1, y->sizep1, cmpstr, len+1, 0, 0); - y->fcncde = URL_SCHEME_UNKNOWN; - inet_pro = shlwapi_schemes; - while (inet_pro->scheme_name) { - if (!strncasecmp(inet_pro->scheme_name, cmpstr, - min(len, lstrlenA(inet_pro->scheme_name)))) { - y->fcncde = inet_pro->scheme_number; - break; - } - inet_pro++; - } - HeapFree(GetProcessHeap(), 0, cmpstr); - return S_OK; -} - -/************************************************************************* - * @ [SHLWAPI.3] - * - * Determine if a file exists locally and is of an executable type. - * - * PARAMS - * lpszFile [O] File to search for - * dwWhich [I] Type of executable to search for - * - * RETURNS - * TRUE If the file was found. lpszFile contains the file name. - * FALSE Otherwise. - * - * NOTES - * lpszPath is modified in place and must be at least MAX_PATH in length. - * If the function returns FALSE, the path is modified to its orginal state. - * If the given path contains an extension or dwWhich is 0, executable - * extensions are not checked. - * - * Ordinals 3-6 are a classic case of MS exposing limited functionality to - * users (here through PathFindOnPath) and keeping advanced functionality for - * their own developers exclusive use. Monopoly, anyone? - */ -BOOL WINAPI SHLWAPI_3(LPSTR lpszFile,DWORD dwWhich) -{ - return SHLWAPI_PathFindLocalExeA(lpszFile,dwWhich); -} - -/************************************************************************* - * @ [SHLWAPI.4] - * - * Unicode version of SHLWAPI_3. - */ -BOOL WINAPI SHLWAPI_4(LPWSTR lpszFile,DWORD dwWhich) -{ - return SHLWAPI_PathFindLocalExeW(lpszFile,dwWhich); -} - -/************************************************************************* - * @ [SHLWAPI.5] - * - * Search a range of paths for a specific type of executable. - * - * PARAMS - * lpszFile [O] File to search for - * lppszOtherDirs [I] Other directories to look in - * dwWhich [I] Type of executable to search for - * - * RETURNS - * Success: TRUE. The path to the executable is stored in sFile. - * Failure: FALSE. The path to the executable is unchanged. - */ -BOOL WINAPI SHLWAPI_5(LPSTR lpszFile,LPCSTR *lppszOtherDirs,DWORD dwWhich) -{ - return SHLWAPI_PathFindOnPathExA(lpszFile,lppszOtherDirs,dwWhich); -} - -/************************************************************************* - * @ [SHLWAPI.6] - * - * Unicode version of SHLWAPI_5. - */ -BOOL WINAPI SHLWAPI_6(LPWSTR lpszFile,LPCWSTR *lppszOtherDirs,DWORD dwWhich) -{ - return SHLWAPI_PathFindOnPathExW(lpszFile,lppszOtherDirs,dwWhich); -} - /************************************************************************* * SHLWAPI_DupSharedHandle * diff --git a/dlls/shlwapi/path.c b/dlls/shlwapi/path.c index fe061749343..1b2db2698e5 100644 --- a/dlls/shlwapi/path.c +++ b/dlls/shlwapi/path.c @@ -35,11 +35,22 @@ #define NO_SHLWAPI_STREAM #include "shlwapi.h" #include "wine/debug.h" -#include "ordinal.h" WINE_DEFAULT_DEBUG_CHANNEL(shell); -/* function pointers for GET_FUNC macro; these need to be global because of gcc bug */ +/* Get a function pointer from a DLL handle */ +#define GET_FUNC(func, module, name, fail) \ + do { \ + if (!func) { \ + if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \ + if (!(func = (void*)GetProcAddress(SHLWAPI_h##module, name))) return fail; \ + } \ + } while (0) + +/* DLL handles for late bound calls */ +extern HMODULE SHLWAPI_hshell32; + +/* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */ static BOOL (WINAPI *pIsNetDrive)(DWORD); /************************************************************************* @@ -1035,33 +1046,11 @@ int WINAPI PathParseIconLocationW(LPWSTR lpszPath) } /************************************************************************* - * SHLWAPI_PathFindLocalExeA + * @ [SHLWAPI.4] * - * Internal implementation of SHLWAPI_3. + * Unicode version of SHLWAPI_3. */ -BOOL WINAPI SHLWAPI_PathFindLocalExeA (LPSTR lpszPath, DWORD dwWhich) -{ - BOOL bRet = FALSE; - - TRACE("(%s,%ld)\n", debugstr_a(lpszPath), dwWhich); - - if (lpszPath) - { - WCHAR szPath[MAX_PATH]; - MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH); - bRet = SHLWAPI_PathFindLocalExeW(szPath, dwWhich); - if (bRet) - WideCharToMultiByte(0,0,szPath,-1,lpszPath,MAX_PATH,0,0); - } - return bRet; -} - -/************************************************************************* - * SHLWAPI_PathFindLocalExeW - * - * Internal implementation of SHLWAPI_4. - */ -BOOL WINAPI SHLWAPI_PathFindLocalExeW (LPWSTR lpszPath, DWORD dwWhich) +BOOL WINAPI SHLWAPI_4(LPWSTR lpszPath,DWORD dwWhich) { static const WCHAR pszExts[7][5] = { { '.', 'p', 'i', 'f', '0'}, { '.', 'c', 'o', 'm', '0'}, @@ -1100,6 +1089,46 @@ BOOL WINAPI SHLWAPI_PathFindLocalExeW (LPWSTR lpszPath, DWORD dwWhich) return PathFileExistsW(lpszPath); } +/************************************************************************* + * @ [SHLWAPI.3] + * + * Determine if a file exists locally and is of an executable type. + * + * PARAMS + * lpszPath [O] File to search for + * dwWhich [I] Type of executable to search for + * + * RETURNS + * TRUE If the file was found. lpszFile contains the file name. + * FALSE Otherwise. + * + * NOTES + * lpszPath is modified in place and must be at least MAX_PATH in length. + * If the function returns FALSE, the path is modified to its orginal state. + * If the given path contains an extension or dwWhich is 0, executable + * extensions are not checked. + * + * Ordinals 3-6 are a classic case of MS exposing limited functionality to + * users (here through PathFindOnPath) and keeping advanced functionality for + * their own developers exclusive use. Monopoly, anyone? + */ +BOOL WINAPI SHLWAPI_3(LPSTR lpszPath,DWORD dwWhich) +{ + BOOL bRet = FALSE; + + TRACE("(%s,%ld)\n", debugstr_a(lpszPath), dwWhich); + + if (lpszPath) + { + WCHAR szPath[MAX_PATH]; + MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH); + bRet = SHLWAPI_4(szPath, dwWhich); + if (bRet) + WideCharToMultiByte(0,0,szPath,-1,lpszPath,MAX_PATH,0,0); + } + return bRet; +} + /************************************************************************* * SHLWAPI_PathFindInOtherDirs * @@ -1120,7 +1149,7 @@ static BOOL WINAPI SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich) GetSystemDirectoryW(buff, MAX_PATH); if (!PathAppendW(buff, lpszFile)) return FALSE; - if (SHLWAPI_PathFindLocalExeW(buff, dwWhich)) + if (SHLWAPI_4(buff, dwWhich)) { strcpyW(lpszFile, buff); return TRUE; @@ -1128,7 +1157,7 @@ static BOOL WINAPI SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich) GetWindowsDirectoryW(buff, MAX_PATH); if (!PathAppendW(buff, szSystem ) || !PathAppendW(buff, lpszFile)) return FALSE; - if (SHLWAPI_PathFindLocalExeW(buff, dwWhich)) + if (SHLWAPI_4(buff, dwWhich)) { strcpyW(lpszFile, buff); return TRUE; @@ -1136,7 +1165,7 @@ static BOOL WINAPI SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich) GetWindowsDirectoryW(buff, MAX_PATH); if (!PathAppendW(buff, lpszFile)) return FALSE; - if (SHLWAPI_PathFindLocalExeW(buff, dwWhich)) + if (SHLWAPI_4(buff, dwWhich)) { strcpyW(lpszFile, buff); return TRUE; @@ -1167,7 +1196,7 @@ static BOOL WINAPI SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich) if (!PathAppendW(buff, lpszFile)) return FALSE; - if (SHLWAPI_PathFindLocalExeW(buff, dwWhich)) + if (SHLWAPI_4(buff, dwWhich)) { strcpyW(lpszFile, buff); free(lpszPATH); @@ -1178,13 +1207,21 @@ static BOOL WINAPI SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich) return FALSE; } - /************************************************************************* - * SHLWAPI_PathFindOnPathExA + * @ [SHLWAPI.5] * - * Internal implementation of SHLWAPI_5 + * Search a range of paths for a specific type of executable. + * + * PARAMS + * lpszFile [O] File to search for + * lppszOtherDirs [I] Other directories to look in + * dwWhich [I] Type of executable to search for + * + * RETURNS + * Success: TRUE. The path to the executable is stored in sFile. + * Failure: FALSE. The path to the executable is unchanged. */ -BOOL WINAPI SHLWAPI_PathFindOnPathExA(LPSTR lpszFile, LPCSTR *lppszOtherDirs, DWORD dwWhich) +BOOL WINAPI SHLWAPI_5(LPSTR lpszFile,LPCSTR *lppszOtherDirs,DWORD dwWhich) { WCHAR szFile[MAX_PATH]; WCHAR buff[MAX_PATH]; @@ -1206,7 +1243,7 @@ BOOL WINAPI SHLWAPI_PathFindOnPathExA(LPSTR lpszFile, LPCSTR *lppszOtherDirs, DW { MultiByteToWideChar(0,0,*lpszOtherPath,-1,szOther,MAX_PATH); PathCombineW(buff, szOther, szFile); - if (SHLWAPI_PathFindLocalExeW(buff, dwWhich)) + if (SHLWAPI_4(buff, dwWhich)) { WideCharToMultiByte(0,0,buff,-1,lpszFile,MAX_PATH,0,0); return TRUE; @@ -1224,11 +1261,11 @@ BOOL WINAPI SHLWAPI_PathFindOnPathExA(LPSTR lpszFile, LPCSTR *lppszOtherDirs, DW } /************************************************************************* - * SHLWAPI_PathFindOnPathExW + * @ [SHLWAPI.6] * - * Internal implementation of SHLWAPI_6. + * Unicode version of SHLWAPI_5. */ -BOOL WINAPI SHLWAPI_PathFindOnPathExW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs, DWORD dwWhich) +BOOL WINAPI SHLWAPI_6(LPWSTR lpszFile,LPCWSTR *lppszOtherDirs,DWORD dwWhich) { WCHAR buff[MAX_PATH]; @@ -1244,7 +1281,7 @@ BOOL WINAPI SHLWAPI_PathFindOnPathExW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs, while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0]) { PathCombineW(buff, *lpszOtherPath, lpszFile); - if (SHLWAPI_PathFindLocalExeW(buff, dwWhich)) + if (SHLWAPI_4(buff, dwWhich)) { strcpyW(lpszFile, buff); return TRUE; @@ -1272,7 +1309,7 @@ BOOL WINAPI SHLWAPI_PathFindOnPathExW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs, BOOL WINAPI PathFindOnPathA(LPSTR lpszFile, LPCSTR *lppszOtherDirs) { TRACE("(%s,%p)\n", debugstr_a(lpszFile), lppszOtherDirs); - return SHLWAPI_PathFindOnPathExA(lpszFile, lppszOtherDirs, 0); + return SHLWAPI_5(lpszFile, lppszOtherDirs, 0); } /************************************************************************* @@ -1280,10 +1317,10 @@ BOOL WINAPI PathFindOnPathA(LPSTR lpszFile, LPCSTR *lppszOtherDirs) * * See PathFindOnPathA. */ -BOOL WINAPI PathFindOnPathW (LPWSTR lpszFile, LPCWSTR *lppszOtherDirs) +BOOL WINAPI PathFindOnPathW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs) { TRACE("(%s,%p)\n", debugstr_w(lpszFile), lppszOtherDirs); - return SHLWAPI_PathFindOnPathExW(lpszFile,lppszOtherDirs, 0); + return SHLWAPI_6(lpszFile,lppszOtherDirs, 0); } /************************************************************************* @@ -1836,47 +1873,6 @@ BOOL WINAPI PathIsSameRootW(LPCWSTR lpszPath1, LPCWSTR lpszPath2) return TRUE; } -/************************************************************************* - * PathIsURLA [SHLWAPI.@] - * - * Check if the given path is a URL. - * - * PARAMS - * lpszPath [I] Path to check. - * - * RETURNS - * TRUE if lpszPath is a URL. - * FALSE if lpszPath is NULL or not a URL. - */ -BOOL WINAPI PathIsURLA(LPCSTR lpstrPath) -{ - UNKNOWN_SHLWAPI_1 base; - DWORD res1; - - if (!lpstrPath || !*lpstrPath) return FALSE; - - /* get protocol */ - base.size = sizeof(base); - res1 = SHLWAPI_1(lpstrPath, &base); - return (base.fcncde > 0); -} - -/************************************************************************* - * PathIsURLW [SHLWAPI.@] - */ -BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath) -{ - UNKNOWN_SHLWAPI_2 base; - DWORD res1; - - if (!lpstrPath || !*lpstrPath) return FALSE; - - /* get protocol */ - base.size = sizeof(base); - res1 = SHLWAPI_2(lpstrPath, &base); - return (base.fcncde > 0); -} - /************************************************************************* * PathIsContentTypeA [SHLWAPI.@] * diff --git a/dlls/shlwapi/regstream.c b/dlls/shlwapi/regstream.c index 64400f8a482..49f3a3b207f 100644 --- a/dlls/shlwapi/regstream.c +++ b/dlls/shlwapi/regstream.c @@ -505,3 +505,43 @@ IStream * WINAPI SHLWAPI_12(LPBYTE lpbData, DWORD dwDataLen) } return iStrmRet; } + +/************************************************************************* + * SHCreateStreamWrapper [SHLWAPI.@] + * + * Create a stream on a block of memory. + * + * PARAMS + * lpbData [I] Memory block to create the stream on + * dwDataLen [I] Length of data block + * dwReserved [I] Reserved, Must be 0. + * lppStream [O] Destination for stream object + * + * RETURNS + * Success: S_OK. lppStream contains the new stream object. + * Failure: E_INVALIDARG, if any parameters are invalid, + * E_OUTOFMEMORY if memory allocation fails. + * + * NOTES + * The stream assumes ownership of the memory passed to it. + */ +HRESULT WINAPI SHCreateStreamWrapper(LPBYTE lpbData, DWORD dwDataLen, + DWORD dwReserved, IStream **lppStream) +{ + IStream* lpStream; + + if (lppStream) + *lppStream = NULL; + + if(dwReserved || !lppStream) + return E_INVALIDARG; + + lpStream = IStream_Create((HKEY)0, lpbData, dwDataLen); + + if(!lpStream) + return E_OUTOFMEMORY; + + IStream_QueryInterface(lpStream, &IID_IStream, (void**)lppStream); + IStream_Release(lpStream); + return S_OK; +} diff --git a/dlls/shlwapi/shlwapi.spec b/dlls/shlwapi/shlwapi.spec index 193bb9d2bb4..cbd02e00722 100644 --- a/dlls/shlwapi/shlwapi.spec +++ b/dlls/shlwapi/shlwapi.spec @@ -623,10 +623,10 @@ init SHLWAPI_LibMain @ stdcall StrCpyW (ptr wstr) StrCpyW @ stdcall StrDupA (str) StrDupA @ stdcall StrDupW (wstr) StrDupW -@ stdcall StrFormatByteSizeA(long str long) StrFormatByteSizeA -@ stdcall StrFormatByteSizeW(long wstr long) StrFormatByteSizeW -@ stdcall StrFromTimeIntervalA(str long long long) StrFromTimeIntervalA -@ stdcall StrFromTimeIntervalW(wstr long long long) StrFromTimeIntervalW +@ stdcall StrFormatByteSizeA(long ptr long) StrFormatByteSizeA +@ stdcall StrFormatByteSizeW(long long ptr long) StrFormatByteSizeW +@ stdcall StrFromTimeIntervalA(ptr long long long) StrFromTimeIntervalA +@ stdcall StrFromTimeIntervalW(ptr long long long) StrFromTimeIntervalW @ stdcall StrIsIntlEqualA(long str str long) StrIsIntlEqualA @ stdcall StrIsIntlEqualW(long wstr wstr long) StrIsIntlEqualW @ stdcall StrNCatA(str str long) StrNCatA @@ -711,7 +711,7 @@ init SHLWAPI_LibMain @ stdcall SHCreateStreamOnFileA(str long ptr) SHCreateStreamOnFileA @ stdcall SHCreateStreamOnFileW(wstr long ptr) SHCreateStreamOnFileW @ stdcall SHCreateStreamOnFileEx(wstr long long long ptr ptr) SHCreateStreamOnFileEx -@ stub SHCreateStreamWrapper +@ stdcall SHCreateStreamWrapper(ptr ptr long ptr) SHCreateStreamWrapper @ stdcall SHGetThreadRef (ptr) SHGetThreadRef @ stdcall SHRegDuplicateHKey (long) SHRegDuplicateHKey @ stdcall SHRegSetPathA(long str str str long) SHRegSetPathA @@ -722,6 +722,7 @@ init SHLWAPI_LibMain @ stdcall SHSkipJunction(ptr ptr) SHSkipJunction @ stdcall SHStrDupA (str ptr) SHStrDupA @ stdcall SHStrDupW (wstr ptr) SHStrDupW -@ stub StrFormatByteSize64A +@ stdcall StrFormatByteSize64A(long long ptr long) StrFormatByteSize64A @ stdcall StrFormatKBSizeA(long long str long) StrFormatKBSizeA @ stdcall StrFormatKBSizeW(long long wstr long) StrFormatKBSizeW +@ stdcall StrCmpLogicalW(wstr wstr) StrCmpLogicalW diff --git a/dlls/shlwapi/string.c b/dlls/shlwapi/string.c index 45db4982032..fe466eb28d9 100644 --- a/dlls/shlwapi/string.c +++ b/dlls/shlwapi/string.c @@ -23,6 +23,7 @@ #include "wine/port.h" #include +#include #include #include #include @@ -1493,40 +1494,6 @@ HRESULT WINAPI StrRetToStrW(LPSTRRET pstr, const ITEMIDLIST * pidl, LPWSTR* ppsz return ret; } -/************************************************************************* - * StrFormatByteSizeA [SHLWAPI.@] - */ -LPSTR WINAPI StrFormatByteSizeA ( DWORD dw, LPSTR pszBuf, UINT cchBuf ) -{ char buf[64]; - TRACE("%lx %p %i\n", dw, pszBuf, cchBuf); - if ( dw<1024L ) - { sprintf (buf,"%ld bytes", dw); - } - else if ( dw<1048576L) - { sprintf (buf,"%3.1f KB", (FLOAT)dw/1024); - } - else if ( dw < 1073741824L) - { sprintf (buf,"%3.1f MB", (FLOAT)dw/1048576L); - } - else - { sprintf (buf,"%3.1f GB", (FLOAT)dw/1073741824L); - } - lstrcpynA (pszBuf, buf, cchBuf); - return pszBuf; -} - -/************************************************************************* - * StrFormatByteSizeW [SHLWAPI.@] - */ -LPWSTR WINAPI StrFormatByteSizeW ( DWORD dw, LPWSTR pszBuf, UINT cchBuf ) -{ - char buf[64]; - StrFormatByteSizeA( dw, buf, sizeof(buf) ); - if (!MultiByteToWideChar( CP_ACP, 0, buf, -1, pszBuf, cchBuf ) && cchBuf) - pszBuf[cchBuf-1] = 0; - return pszBuf; -} - /************************************************************************* * StrFormatKBSizeA [SHLWAPI.@] * @@ -2123,3 +2090,212 @@ LPWSTR WINAPI SHLWAPI_400(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen) } return lpszDest; } + +/************************************************************************* + * StrCmpLogicalW [SHLWAPI.@] + * + * Compare two strings, ignoring case and comparing digits as numbers. + * + * PARAMS + * lpszStr [I] First string to compare + * lpszComp [I] Second string to compare + * iLen [I] Length to compare + * + * RETURNS + * TRUE If the strings are equal. + * FALSE Otherwise. + */ +INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp) +{ + INT iDiff; + + TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp)); + + if (lpszStr && lpszComp) + { + while (*lpszStr) + { + if (!*lpszComp) + return 1; + else if (isdigitW(*lpszStr)) + { + int iStr, iComp; + + if (!isdigitW(*lpszComp)) + return -1; + + /* Compare the numbers */ + StrToIntExW(lpszStr, 0, &iStr); + StrToIntExW(lpszComp, 0, &iComp); + + if (iStr < iComp) + return -1; + else if (iStr > iComp) + return 1; + + /* Skip */ + while (isdigitW(*lpszStr)) + lpszStr++; + while (isdigitW(*lpszComp)) + lpszComp++; + } + else if (isdigitW(*lpszComp)) + return 1; + else + { + iDiff = SHLWAPI_ChrCmpHelperA(*lpszStr,*lpszComp,NORM_IGNORECASE); + if (iDiff > 0) + return 1; + else if (iDiff < 0) + return -1; + + lpszStr++; + lpszComp++; + } + } + if (*lpszComp) + return -1; + } + return 0; +} + +/* Structure for formatting byte strings */ +typedef struct tagSHLWAPI_BYTEFORMATS +{ + LONGLONG dLimit; + double dDivisor; + double dNormaliser; + LPCSTR lpszFormat; + CHAR wPrefix; +} SHLWAPI_BYTEFORMATS; + +/************************************************************************* + * StrFormatByteSize64A [SHLWAPI.@] + * + * Create a string containing an abbreviated byte count of up to 2^63-1. + * + * PARAMS + * llBytes [I] Byte size to format + * lpszDest [I] Destination for formatted string + * cchMax [I] Size of lpszDest + * + * RETURNS + * lpszDest. + * + * NOTES + * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW. + */ +LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax) +{ + static const char szBytes[] = "%ld bytes"; + static const char sz3_0[] = "%3.0f"; + static const char sz3_1[] = "%3.1f"; + static const char sz3_2[] = "%3.2f"; + + static const SHLWAPI_BYTEFORMATS bfFormats[] = + { + { 10240, 10.24, 100.0, sz3_2, 'K' }, /* 10 KB */ + { 102400, 102.4, 10.0, sz3_1, 'K' }, /* 100 KB */ + { 1024000, 1024.0, 1.0, sz3_0, 'K' }, /* 1000 KB */ + { 10485760, 10485.76, 100.0, sz3_2, 'M' }, /* 10 MB */ + { 104857600, 104857.6, 10.0, sz3_1, 'M' }, /* 100 MB */ + { 1048576000, 1048576.0, 1.0, sz3_0, 'M' }, /* 1000 MB */ + { 10737418240, 10737418.24, 100.0, sz3_2, 'G' }, /* 10 GB */ + { 107374182400, 107374182.4, 10.0, sz3_1, 'G' }, /* 100 GB */ + { 1073741824000, 1073741824.0, 1.0, sz3_0, 'G' }, /* 1000 GB */ + { 10995116277760, 10485.76, 100.0, sz3_2, 'T' }, /* 10 TB */ + { 109951162777600, 104857.6, 10.0, sz3_1, 'T' }, /* 100 TB */ + { 1099511627776000, 1048576.0, 1.0, sz3_0, 'T' }, /* 1000 TB */ + { 11258999068426240, 10737418.24, 100.00, sz3_2, 'P' }, /* 10 PB */ + { 112589990684262400, 107374182.4, 10.00, sz3_1, 'P' }, /* 100 PB */ + { 1125899906842624000, 1073741824.0, 1.00, sz3_0, 'P' }, /* 1000 PB */ + { 0, 10995116277.76, 100.00, sz3_2, 'E' } /* EB's, catch all */ + }; + char szBuff[32]; + char szAdd[4]; + double dBytes; + UINT i = 0; + + TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax); + + if (!lpszDest || !cchMax) + return lpszDest; + + if (llBytes < 1024) /* 1K */ + { + snprintf (lpszDest, cchMax, szBytes, (long)llBytes); + return lpszDest; + } + + /* Note that if this loop completes without finding a match, i will be + * pointing at the last entry, which is a catch all for > 1000 PB + */ + while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1) + { + if (llBytes < bfFormats[i].dLimit) + break; + i++; + } + /* Above 1 TB we encounter problems with FP accuracy. So for amounts above + * this number we integer shift down by 1 MB first. The table above has + * the divisors scaled down from the '< 10 TB' entry onwards, to account + * for this. We also add a small fudge factor to get the correct result for + * counts that lie exactly on a 1024 byte boundary. + */ + if (i > 8) + dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */ + else + dBytes = (double)llBytes + 0.00001; + + dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser; + + sprintf(szBuff, bfFormats[i].lpszFormat, dBytes); + szAdd[0] = ' '; + szAdd[1] = bfFormats[i].wPrefix; + szAdd[2] = 'B'; + szAdd[3] = '\0'; + strcat(szBuff, szAdd); + strncpy(lpszDest, szBuff, cchMax); + return lpszDest; +} + +/************************************************************************* + * StrFormatByteSizeW [SHLWAPI.@] + * + * See StrFormatByteSize64A. + */ +LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, + UINT cchMax) +{ + char szBuff[32]; + + StrFormatByteSize64A(llBytes, szBuff, sizeof(szBuff)); + + if (lpszDest) + MultiByteToWideChar(CP_ACP, 0, szBuff, -1, lpszDest, cchMax); + return lpszDest; +} + +/************************************************************************* + * StrFormatByteSizeA [SHLWAPI.@] + * + * Create a string containing an abbreviated byte count of up to 2^31-1. + * + * PARAMS + * dwBytes [I] Byte size to format + * lpszDest [I] Destination for formatted string + * cchMax [I] Size of lpszDest + * + * RETURNS + * lpszDest. + * + * NOTES + * The ASCII and Unicode versions of this function accept a different + * integer size for dwBytes. See StrFormatByteSize64A. + */ +LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax) +{ + TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax); + + return StrFormatByteSize64A(dwBytes, lpszDest, cchMax); +} diff --git a/dlls/shlwapi/thread.c b/dlls/shlwapi/thread.c index 0a3f187b12c..4b97af22e57 100644 --- a/dlls/shlwapi/thread.c +++ b/dlls/shlwapi/thread.c @@ -30,14 +30,26 @@ #define NO_SHLWAPI_STREAM #define NO_SHLWAPI_USER #include "shlwapi.h" -#include "ordinal.h" WINE_DEFAULT_DEBUG_CHANNEL(shell); -extern DWORD SHLWAPI_ThreadRef_index; /* Initialised in shlwapi_main.c */ +/* Get a function pointer from a DLL handle */ +#define GET_FUNC(func, module, name, fail) \ + do { \ + if (!func) { \ + if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \ + if (!(func = (void*)GetProcAddress(SHLWAPI_h##module, name))) return fail; \ + } \ + } while (0) +/* DLL handles for late bound calls */ +extern HMODULE SHLWAPI_hshell32; + +/* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */ static HRESULT (WINAPI *pSHGetInstanceExplorer)(IUnknown**); +extern DWORD SHLWAPI_ThreadRef_index; /* Initialised in shlwapi_main.c */ + DWORD WINAPI SHLWAPI_23(REFGUID,LPSTR,INT); /************************************************************************** diff --git a/dlls/shlwapi/url.c b/dlls/shlwapi/url.c index 7a0048ece0f..387ae9da569 100644 --- a/dlls/shlwapi/url.c +++ b/dlls/shlwapi/url.c @@ -30,10 +30,63 @@ #define NO_SHLWAPI_STREAM #include "shlwapi.h" #include "wine/debug.h" -#include "ordinal.h" WINE_DEFAULT_DEBUG_CHANNEL(shell); +/* The following schemes were identified in the native version of + * SHLWAPI.DLL version 5.50 + */ +typedef enum { + URL_SCHEME_INVALID = -1, + URL_SCHEME_UNKNOWN = 0, + URL_SCHEME_FTP, + URL_SCHEME_HTTP, + URL_SCHEME_GOPHER, + URL_SCHEME_MAILTO, + URL_SCHEME_NEWS, + URL_SCHEME_NNTP, + URL_SCHEME_TELNET, + URL_SCHEME_WAIS, + URL_SCHEME_FILE, + URL_SCHEME_MK, + URL_SCHEME_HTTPS, + URL_SCHEME_SHELL, + URL_SCHEME_SNEWS, + URL_SCHEME_LOCAL, + URL_SCHEME_JAVASCRIPT, + URL_SCHEME_VBSCRIPT, + URL_SCHEME_ABOUT, + URL_SCHEME_RES, + URL_SCHEME_MAXVALUE +} URL_SCHEME; + +typedef struct { + URL_SCHEME scheme_number; + LPCSTR scheme_name; +} SHL_2_inet_scheme; + +static const SHL_2_inet_scheme shlwapi_schemes[] = { + {URL_SCHEME_FTP, "ftp"}, + {URL_SCHEME_HTTP, "http"}, + {URL_SCHEME_GOPHER, "gopher"}, + {URL_SCHEME_MAILTO, "mailto"}, + {URL_SCHEME_NEWS, "news"}, + {URL_SCHEME_NNTP, "nntp"}, + {URL_SCHEME_TELNET, "telnet"}, + {URL_SCHEME_WAIS, "wais"}, + {URL_SCHEME_FILE, "file"}, + {URL_SCHEME_MK, "mk"}, + {URL_SCHEME_HTTPS, "https"}, + {URL_SCHEME_SHELL, "shell"}, + {URL_SCHEME_SNEWS, "snews"}, + {URL_SCHEME_LOCAL, "local"}, + {URL_SCHEME_JAVASCRIPT, "javascript"}, + {URL_SCHEME_VBSCRIPT, "vbscript"}, + {URL_SCHEME_ABOUT, "about"}, + {URL_SCHEME_RES, "res"}, + {0, 0} +}; + typedef struct { LPCWSTR pScheme; /* [out] start of scheme */ DWORD szScheme; /* [out] size of scheme (until colon) */ @@ -56,6 +109,24 @@ typedef enum { USERPASS, } WINE_URL_SCAN_TYPE; +typedef struct { + INT size; /* [in] (always 0x18) */ + LPCSTR ap1; /* [out] start of scheme */ + INT sizep1; /* [out] size of scheme (until colon) */ + LPCSTR ap2; /* [out] pointer following first colon */ + INT sizep2; /* [out] size of remainder */ + INT fcncde; /* [out] function match of p1 (0 if unknown) */ +} UNKNOWN_SHLWAPI_1; + +typedef struct { + INT size; /* [in] (always 0x18) */ + LPCWSTR ap1; /* [out] start of scheme */ + INT sizep1; /* [out] size of scheme (until colon) */ + LPCWSTR ap2; /* [out] pointer following first colon */ + INT sizep2; /* [out] size of remainder */ + INT fcncde; /* [out] function match of p1 (0 if unknown) */ +} UNKNOWN_SHLWAPI_2; + static const CHAR hexDigits[] = "0123456789ABCDEF"; static const WCHAR fileW[] = {'f','i','l','e','\0'}; @@ -185,6 +256,122 @@ static BOOL URL_JustLocation(LPCWSTR str) } +/************************************************************************* + * @ [SHLWAPI.1] + * + * Identifies the Internet "scheme" in the passed string. ASCII based. + * Also determines start and length of item after the ':' + */ +DWORD WINAPI SHLWAPI_1 (LPCSTR x, UNKNOWN_SHLWAPI_1 *y) +{ + DWORD cnt; + const SHL_2_inet_scheme *inet_pro; + + y->fcncde = URL_SCHEME_INVALID; + if (y->size != 0x18) return E_INVALIDARG; + /* FIXME: leading white space generates error of 0x80041001 which + * is undefined + */ + if (*x <= ' ') return 0x80041001; + cnt = 0; + y->sizep1 = 0; + y->ap1 = x; + while (*x) { + if (*x == ':') { + y->sizep1 = cnt; + cnt = -1; + y->ap2 = x+1; + break; + } + x++; + cnt++; + } + + /* check for no scheme in string start */ + /* (apparently schemes *must* be larger than a single character) */ + if ((*x == '\0') || (y->sizep1 <= 1)) { + y->ap1 = 0; + return 0x80041001; + } + + /* found scheme, set length of remainder */ + y->sizep2 = lstrlenA(y->ap2); + + /* see if known scheme and return indicator number */ + y->fcncde = URL_SCHEME_UNKNOWN; + inet_pro = shlwapi_schemes; + while (inet_pro->scheme_name) { + if (!strncasecmp(inet_pro->scheme_name, y->ap1, + min(y->sizep1, lstrlenA(inet_pro->scheme_name)))) { + y->fcncde = inet_pro->scheme_number; + break; + } + inet_pro++; + } + return S_OK; +} + +/************************************************************************* + * @ [SHLWAPI.2] + * + * Identifies the Internet "scheme" in the passed string. UNICODE based. + * Also determines start and length of item after the ':' + */ +DWORD WINAPI SHLWAPI_2 (LPCWSTR x, UNKNOWN_SHLWAPI_2 *y) +{ + DWORD cnt; + const SHL_2_inet_scheme *inet_pro; + LPSTR cmpstr; + INT len; + + y->fcncde = URL_SCHEME_INVALID; + if (y->size != 0x18) return E_INVALIDARG; + /* FIXME: leading white space generates error of 0x80041001 which + * is undefined + */ + if (*x <= L' ') return 0x80041001; + cnt = 0; + y->sizep1 = 0; + y->ap1 = x; + while (*x) { + if (*x == L':') { + y->sizep1 = cnt; + cnt = -1; + y->ap2 = x+1; + break; + } + x++; + cnt++; + } + + /* check for no scheme in string start */ + /* (apparently schemes *must* be larger than a single character) */ + if ((*x == L'\0') || (y->sizep1 <= 1)) { + y->ap1 = 0; + return 0x80041001; + } + + /* found scheme, set length of remainder */ + y->sizep2 = lstrlenW(y->ap2); + + /* see if known scheme and return indicator number */ + len = WideCharToMultiByte(0, 0, y->ap1, y->sizep1, 0, 0, 0, 0); + cmpstr = (LPSTR)HeapAlloc(GetProcessHeap(), 0, len+1); + WideCharToMultiByte(0, 0, y->ap1, y->sizep1, cmpstr, len+1, 0, 0); + y->fcncde = URL_SCHEME_UNKNOWN; + inet_pro = shlwapi_schemes; + while (inet_pro->scheme_name) { + if (!strncasecmp(inet_pro->scheme_name, cmpstr, + min(len, lstrlenA(inet_pro->scheme_name)))) { + y->fcncde = inet_pro->scheme_number; + break; + } + inet_pro++; + } + HeapFree(GetProcessHeap(), 0, cmpstr); + return S_OK; +} + /************************************************************************* * UrlCanonicalizeA [SHLWAPI.@] * @@ -1753,3 +1940,44 @@ HRESULT WINAPI UrlGetPartW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, } return ret; } + +/************************************************************************* + * PathIsURLA [SHLWAPI.@] + * + * Check if the given path is a URL. + * + * PARAMS + * lpszPath [I] Path to check. + * + * RETURNS + * TRUE if lpszPath is a URL. + * FALSE if lpszPath is NULL or not a URL. + */ +BOOL WINAPI PathIsURLA(LPCSTR lpstrPath) +{ + UNKNOWN_SHLWAPI_1 base; + DWORD res1; + + if (!lpstrPath || !*lpstrPath) return FALSE; + + /* get protocol */ + base.size = sizeof(base); + res1 = SHLWAPI_1(lpstrPath, &base); + return (base.fcncde > 0); +} + +/************************************************************************* + * PathIsURLW [SHLWAPI.@] + */ +BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath) +{ + UNKNOWN_SHLWAPI_2 base; + DWORD res1; + + if (!lpstrPath || !*lpstrPath) return FALSE; + + /* get protocol */ + base.size = sizeof(base); + res1 = SHLWAPI_2(lpstrPath, &base); + return (base.fcncde > 0); +} diff --git a/include/shlwapi.h b/include/shlwapi.h index 2201ac80ad8..f7856dd053a 100644 --- a/include/shlwapi.h +++ b/include/shlwapi.h @@ -709,8 +709,17 @@ HRESULT WINAPI SHStrDupW(LPCWSTR,WCHAR**); #define SHStrDup WINELIB_NAME_AW(SHStrDup) LPSTR WINAPI StrFormatByteSizeA (DWORD,LPSTR,UINT); -LPWSTR WINAPI StrFormatByteSizeW (DWORD,LPWSTR,UINT); -#define StrFormatByteSize WINELIB_NAME_AW(StrFormatByteSize) + +/* A/W Pairing is broken for this function */ +LPSTR WINAPI StrFormatByteSize64A (LONGLONG,LPSTR,UINT); +LPWSTR WINAPI StrFormatByteSizeW (LONGLONG,LPWSTR,UINT); +#ifndef __WINE__ +#ifdef UNICODE +#define StrFormatByteSize StrFormatByteSizeW +#else +#define StrFormatByteSize StrFormatByteSize64A +#endif +#endif int WINAPI StrFromTimeIntervalA(LPSTR,UINT,DWORD,int); int WINAPI StrFromTimeIntervalW(LPWSTR,UINT,DWORD,int);