oleaut32: Don't complain when PICTDESC->cbSizeofstruct is 0.
[wine] / dlls / shlwapi / path.c
index 92b2843..32e7b74 100644 (file)
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include "config.h"
@@ -32,6 +32,7 @@
 #include "wingdi.h"
 #include "winuser.h"
 #include "winreg.h"
+#include "winternl.h"
 #define NO_SHLWAPI_STREAM
 #include "shlwapi.h"
 #include "wine/debug.h"
@@ -140,11 +141,11 @@ LPSTR WINAPI PathCombineA(LPSTR lpszDest, LPCSTR lpszDir, LPCSTR lpszFile)
     WCHAR szDir[MAX_PATH];
     WCHAR szFile[MAX_PATH];
     if (lpszDir)
-      MultiByteToWideChar(0,0,lpszDir,-1,szDir,MAX_PATH);
+      MultiByteToWideChar(CP_ACP,0,lpszDir,-1,szDir,MAX_PATH);
     if (lpszFile)
-      MultiByteToWideChar(0,0,lpszFile,-1,szFile,MAX_PATH);
+      MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH);
     PathCombineW(szDest, lpszDir ? szDir : NULL, lpszFile ? szFile : NULL);
-    WideCharToMultiByte(0,0,szDest,-1,lpszDest,MAX_PATH,0,0);
+    WideCharToMultiByte(CP_ACP,0,szDest,-1,lpszDest,MAX_PATH,0,0);
   }
   return lpszDest;
 }
@@ -162,19 +163,19 @@ LPWSTR WINAPI PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile)
   TRACE("(%p,%s,%s)\n", lpszDest, debugstr_w(lpszDir), debugstr_w(lpszFile));
 
   if (!lpszDest || (!lpszDir && !lpszFile))
-    return lpszDest; /* Invalid parameters */
+    return NULL; /* Invalid parameters */
 
-  if (!lpszFile || !*lpszFile)
+  if ((!lpszFile || !*lpszFile) && lpszDir)
   {
     /* Use dir only */
-    strncpyW(szTemp, lpszDir, MAX_PATH);
+    lstrcpynW(szTemp, lpszDir, MAX_PATH);
   }
   else if (!lpszDir || !*lpszDir || !PathIsRelativeW(lpszFile))
   {
     if (!lpszDir || !*lpszDir || *lpszFile != '\\' || PathIsUNCW(lpszFile))
     {
       /* Use file only */
-      strncpyW(szTemp, lpszFile, MAX_PATH);
+      lstrcpynW(szTemp, lpszFile, MAX_PATH);
     }
     else
     {
@@ -187,7 +188,7 @@ LPWSTR WINAPI PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile)
 
   if (bUseBoth)
   {
-    strncpyW(szTemp, lpszDir, MAX_PATH);
+    lstrcpynW(szTemp, lpszDir, MAX_PATH);
     if (bStrip)
     {
       PathStripToRootW(szTemp);
@@ -505,9 +506,12 @@ int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath)
 {
   TRACE ("(%s)\n",debugstr_w(lpszPath));
 
-  if (lpszPath && lpszPath[1] == ':' &&
-      tolowerW(*lpszPath) >= 'a' && tolowerW(*lpszPath) <= 'z')
-    return tolowerW(*lpszPath) - 'a';
+  if (lpszPath)
+  {
+      WCHAR tl = tolowerW(lpszPath[0]);
+      if (tl >= 'a' && tl <= 'z' && lpszPath[1] == ':')
+          return tl - 'a';
+  }
   return -1;
 }
 
@@ -1078,7 +1082,7 @@ BOOL WINAPI PathFileExistsDefExtW(LPWSTR lpszPath,DWORD dwWhich)
       int iLen = lstrlenW(lpszPath);
       if (iLen > (MAX_PATH - 5))
         return FALSE;
-      while (dwWhich & 0x1 && iChoose < sizeof(pszExts))
+      while ( (dwWhich & 0x1) && pszExts[iChoose][0] )
       {
         lstrcpyW(lpszPath + iLen, pszExts[iChoose]);
         if (PathFileExistsW(lpszPath))
@@ -1125,10 +1129,10 @@ BOOL WINAPI PathFileExistsDefExtA(LPSTR lpszPath,DWORD dwWhich)
   if (lpszPath)
   {
     WCHAR szPath[MAX_PATH];
-    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
+    MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
     bRet = PathFileExistsDefExtW(szPath, dwWhich);
     if (bRet)
-      WideCharToMultiByte(0,0,szPath,-1,lpszPath,MAX_PATH,0,0);
+      WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0);
   }
   return bRet;
 }
@@ -1140,8 +1144,8 @@ BOOL WINAPI PathFileExistsDefExtA(LPSTR lpszPath,DWORD dwWhich)
  */
 static BOOL WINAPI SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich)
 {
-  static WCHAR szSystem[] = { 'S','y','s','t','e','m','\0'};
-  static WCHAR szPath[] = { 'P','A','T','H','\0'};
+  static const WCHAR szSystem[] = { 'S','y','s','t','e','m','\0'};
+  static const WCHAR szPath[] = { 'P','A','T','H','\0'};
   DWORD dwLenPATH;
   LPCWSTR lpszCurr;
   WCHAR *lpszPATH;
@@ -1238,7 +1242,7 @@ BOOL WINAPI PathFindOnPathExA(LPSTR lpszFile,LPCSTR *lppszOtherDirs,DWORD dwWhic
   if (!lpszFile || !PathIsFileSpecA(lpszFile))
     return FALSE;
 
-  MultiByteToWideChar(0,0,lpszFile,-1,szFile,MAX_PATH);
+  MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH);
 
   /* Search provided directories first */
   if (lppszOtherDirs && *lppszOtherDirs)
@@ -1248,11 +1252,11 @@ BOOL WINAPI PathFindOnPathExA(LPSTR lpszFile,LPCSTR *lppszOtherDirs,DWORD dwWhic
 
     while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0])
     {
-      MultiByteToWideChar(0,0,*lpszOtherPath,-1,szOther,MAX_PATH);
+      MultiByteToWideChar(CP_ACP,0,*lpszOtherPath,-1,szOther,MAX_PATH);
       PathCombineW(buff, szOther, szFile);
       if (PathFileExistsDefExtW(buff, dwWhich))
       {
-        WideCharToMultiByte(0,0,buff,-1,lpszFile,MAX_PATH,0,0);
+        WideCharToMultiByte(CP_ACP,0,buff,-1,lpszFile,MAX_PATH,0,0);
         return TRUE;
       }
       lpszOtherPath++;
@@ -1261,7 +1265,7 @@ BOOL WINAPI PathFindOnPathExA(LPSTR lpszFile,LPCSTR *lppszOtherDirs,DWORD dwWhic
   /* Not found, try system and path dirs */
   if (SHLWAPI_PathFindInOtherDirs(szFile, dwWhich))
   {
-    WideCharToMultiByte(0,0,szFile,-1,lpszFile,MAX_PATH,0,0);
+    WideCharToMultiByte(CP_ACP,0,szFile,-1,lpszFile,MAX_PATH,0,0);
     return TRUE;
   }
   return FALSE;
@@ -1368,10 +1372,10 @@ BOOL WINAPI PathCompactPathExA(LPSTR lpszDest, LPCSTR lpszPath,
     WCHAR szPath[MAX_PATH];
     WCHAR szDest[MAX_PATH];
 
-    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
+    MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
     szDest[0] = '\0';
     bRet = PathCompactPathExW(szDest, szPath, cchMax, dwFlags);
-    WideCharToMultiByte(0,0,szDest,-1,lpszDest,MAX_PATH,0,0);
+    WideCharToMultiByte(CP_ACP,0,szDest,-1,lpszDest,MAX_PATH,0,0);
   }
   return bRet;
 }
@@ -1686,7 +1690,8 @@ BOOL WINAPI PathFileExistsA(LPCSTR lpszPath)
   if (!lpszPath)
     return FALSE;
 
-  iPrevErrMode = SetErrorMode(1);
+  /* Prevent a dialog box if path is on a disk that has been ejected. */
+  iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
   dwAttr = GetFileAttributesA(lpszPath);
   SetErrorMode(iPrevErrMode);
   return dwAttr == INVALID_FILE_ATTRIBUTES ? FALSE : TRUE;
@@ -1707,12 +1712,69 @@ BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
   if (!lpszPath)
     return FALSE;
 
-  iPrevErrMode = SetErrorMode(1);
+  iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
   dwAttr = GetFileAttributesW(lpszPath);
   SetErrorMode(iPrevErrMode);
   return dwAttr == INVALID_FILE_ATTRIBUTES ? FALSE : TRUE;
 }
 
+/*************************************************************************
+ * PathFileExistsAndAttributesA        [SHLWAPI.445]
+ *
+ * Determine if a file exists.
+ *
+ * PARAMS
+ *  lpszPath [I] Path to check
+ *  dwAttr   [O] attributes of file
+ *
+ * RETURNS
+ *  TRUE  If the file exists and is readable
+ *  FALSE Otherwise
+ */
+BOOL WINAPI PathFileExistsAndAttributesA(LPCSTR lpszPath, DWORD *dwAttr)
+{
+  UINT iPrevErrMode;
+  DWORD dwVal = 0;
+
+  TRACE("(%s %p)\n", debugstr_a(lpszPath), dwAttr);
+
+  if (dwAttr)
+    *dwAttr = INVALID_FILE_ATTRIBUTES;
+
+  if (!lpszPath)
+    return FALSE;
+
+  iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+  dwVal = GetFileAttributesA(lpszPath);
+  SetErrorMode(iPrevErrMode);
+  if (dwAttr)
+    *dwAttr = dwVal;
+  return (dwVal != INVALID_FILE_ATTRIBUTES);
+}
+
+/*************************************************************************
+ * PathFileExistsAndAttributesW        [SHLWAPI.446]
+ *
+ * See PathFileExistsA.
+ */
+BOOL WINAPI PathFileExistsAndAttributesW(LPCWSTR lpszPath, DWORD *dwAttr)
+{
+  UINT iPrevErrMode;
+  DWORD dwVal;
+
+  TRACE("(%s %p)\n", debugstr_w(lpszPath), dwAttr);
+
+  if (!lpszPath)
+    return FALSE;
+
+  iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+  dwVal = GetFileAttributesW(lpszPath);
+  SetErrorMode(iPrevErrMode);
+  if (dwAttr)
+    *dwAttr = dwVal;
+  return (dwVal != INVALID_FILE_ATTRIBUTES);
+}
+
 /*************************************************************************
  * PathMatchSingleMaskA        [internal]
  */
@@ -1807,18 +1869,17 @@ BOOL WINAPI PathMatchSpecA(LPCSTR lpszPath, LPCSTR lpszMask)
 
   while (*lpszMask)
   {
+    while (*lpszMask == ' ')
+      lpszMask++; /* Eat leading spaces */
+
     if (PathMatchSingleMaskA(lpszPath, lpszMask))
       return TRUE; /* Matches the current mask */
 
     while (*lpszMask && *lpszMask != ';')
-      lpszMask = CharNextA(lpszMask);
+      lpszMask = CharNextA(lpszMask); /* masks separated by ';' */
 
     if (*lpszMask == ';')
-    {
       lpszMask++;
-      while (*lpszMask == ' ')
-        lpszMask++; /*  masks may be separated by "; " */
-    }
   }
   return FALSE;
 }
@@ -1839,18 +1900,17 @@ BOOL WINAPI PathMatchSpecW(LPCWSTR lpszPath, LPCWSTR lpszMask)
 
   while (*lpszMask)
   {
+    while (*lpszMask == ' ')
+      lpszMask++; /* Eat leading spaces */
+
     if (PathMatchSingleMaskW(lpszPath, lpszMask))
       return TRUE; /* Matches the current path */
 
     while (*lpszMask && *lpszMask != ';')
-      lpszMask++;
+      lpszMask++; /* masks separated by ';' */
 
     if (*lpszMask == ';')
-    {
       lpszMask++;
-      while (*lpszMask == ' ')
-        lpszMask++; /* Masks may be separated by "; " */
-    }
   }
   return FALSE;
 }
@@ -2281,9 +2341,9 @@ BOOL WINAPI PathCanonicalizeA(LPSTR lpszBuf, LPCSTR lpszPath)
   {
     WCHAR szPath[MAX_PATH];
     WCHAR szBuff[MAX_PATH];
-    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
+    MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
     bRet = PathCanonicalizeW(szBuff, szPath);
-    WideCharToMultiByte(0,0,szBuff,-1,lpszBuf,MAX_PATH,0,0);
+    WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszBuf,MAX_PATH,0,0);
   }
   return bRet;
 }
@@ -2457,7 +2517,7 @@ LPWSTR WINAPI PathFindNextComponentW(LPCWSTR lpszPath)
  * RETURNS
  *  TRUE  If the path was modified,
  *  FALSE If lpszPath or lpszExtension are invalid, lpszPath has an
- *        extension allready, or the new path length is too big.
+ *        extension already, or the new path length is too big.
  *
  * FIXME
  *  What version of shlwapi.dll adds "exe" if lpszExtension is NULL? Win2k
@@ -2522,20 +2582,23 @@ BOOL WINAPI PathMakePrettyA(LPSTR lpszPath)
 
   TRACE("(%s)\n", debugstr_a(lpszPath));
 
-  if (!pszIter || !*pszIter)
+  if (!pszIter)
     return FALSE;
 
-  while (*pszIter)
-  {
-    if (islower(*pszIter) || IsDBCSLeadByte(*pszIter))
-      return FALSE; /* Not DOS path */
-    pszIter++;
-  }
-  pszIter = lpszPath + 1;
-  while (*pszIter)
+  if (*pszIter)
   {
-    *pszIter = tolower(*pszIter);
-    pszIter++;
+    do
+    {
+      if (islower(*pszIter) || IsDBCSLeadByte(*pszIter))
+        return FALSE; /* Not DOS path */
+      pszIter++;
+    } while (*pszIter);
+    pszIter = lpszPath + 1;
+    while (*pszIter)
+    {
+      *pszIter = tolower(*pszIter);
+      pszIter++;
+    }
   }
   return TRUE;
 }
@@ -2551,20 +2614,23 @@ BOOL WINAPI PathMakePrettyW(LPWSTR lpszPath)
 
   TRACE("(%s)\n", debugstr_w(lpszPath));
 
-  if (!pszIter || !*pszIter)
+  if (!pszIter)
     return FALSE;
 
-  while (*pszIter)
-  {
-    if (islowerW(*pszIter))
-      return FALSE; /* Not DOS path */
-    pszIter++;
-  }
-  pszIter = lpszPath + 1;
-  while (*pszIter)
+  if (*pszIter)
   {
-    *pszIter = tolowerW(*pszIter);
-    pszIter++;
+    do
+    {
+      if (islowerW(*pszIter))
+        return FALSE; /* Not DOS path */
+      pszIter++;
+    } while (*pszIter);
+    pszIter = lpszPath + 1;
+    while (*pszIter)
+    {
+      *pszIter = tolowerW(*pszIter);
+      pszIter++;
+    }
   }
   return TRUE;
 }
@@ -2709,7 +2775,7 @@ int WINAPI PathCommonPrefixW(LPCWSTR lpszFile1, LPCWSTR lpszFile2, LPWSTR achPat
  *  dx       [I]   Desired width
  *
  * RETURNS
- *  TRUE  If the path was modified.
+ *  TRUE  If the path was modified/went well.
  *  FALSE Otherwise.
  */
 BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR lpszPath, UINT dx)
@@ -2721,9 +2787,9 @@ BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR lpszPath, UINT dx)
   if (lpszPath)
   {
     WCHAR szPath[MAX_PATH];
-    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
+    MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
     bRet = PathCompactPathW(hDC, szPath, dx);
-    WideCharToMultiByte(0,0,szPath,-1,lpszPath,MAX_PATH,0,0);
+    WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0);
   }
   return bRet;
 }
@@ -2745,7 +2811,7 @@ BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR lpszPath, UINT dx)
   TRACE("(%p,%s,%d)\n", hDC, debugstr_w(lpszPath), dx);
 
   if (!lpszPath)
-    return bRet;
+    return FALSE;
 
   if (!hDC)
     hdc = hDC = GetDC(0);
@@ -2780,7 +2846,7 @@ BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR lpszPath, UINT dx)
        * the file name as possible, allowing for the ellipses, e.g:
        * c:\some very long path\filename ==> c:\some v...\filename
        */
-      strncpyW(buff, sFile, MAX_PATH);
+      lstrcpynW(buff, sFile, MAX_PATH);
 
       do
       {
@@ -2822,7 +2888,7 @@ BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR lpszPath, UINT dx)
 
     if (dwLen > MAX_PATH - 3)
       dwLen =  MAX_PATH - 3;
-    strncpyW(buff, sFile, dwLen);
+    lstrcpynW(buff, sFile, dwLen);
 
     do {
       dwLen--;
@@ -2914,7 +2980,7 @@ UINT WINAPI PathGetCharTypeW(WCHAR ch)
  *
  * Internal helper for PathMakeSystemFolderW.
  */
-static BOOL WINAPI SHLWAPI_UseSystemForSystemFolders()
+static BOOL WINAPI SHLWAPI_UseSystemForSystemFolders(void)
 {
   static BOOL bCheckedReg = FALSE;
   static BOOL bUseSystemForSystemFolders = FALSE;
@@ -2953,7 +3019,7 @@ BOOL WINAPI PathMakeSystemFolderA(LPCSTR lpszPath)
   if (lpszPath && *lpszPath)
   {
     WCHAR szPath[MAX_PATH];
-    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
+    MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
     bRet = PathMakeSystemFolderW(szPath);
   }
   return bRet;
@@ -3058,8 +3124,11 @@ BOOL WINAPI PathRenameExtensionW(LPWSTR lpszPath, LPCWSTR lpszExt)
  */
 BOOL WINAPI PathSearchAndQualifyA(LPCSTR lpszPath, LPSTR lpszBuf, UINT cchBuf)
 {
-  FIXME("(%s,%p,0x%08x)-stub\n", debugstr_a(lpszPath), lpszBuf, cchBuf);
-  return FALSE;
+    TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszPath), lpszBuf, cchBuf);
+
+    if(SearchPathA(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL))
+        return TRUE;
+    return !!GetFullPathNameA(lpszPath, cchBuf, lpszBuf, NULL);
 }
 
 /*************************************************************************
@@ -3069,8 +3138,11 @@ BOOL WINAPI PathSearchAndQualifyA(LPCSTR lpszPath, LPSTR lpszBuf, UINT cchBuf)
  */
 BOOL WINAPI PathSearchAndQualifyW(LPCWSTR lpszPath, LPWSTR lpszBuf, UINT cchBuf)
 {
-  FIXME("(%s,%p,0x%08x)-stub\n", debugstr_w(lpszPath), lpszBuf, cchBuf);
-  return FALSE;
+    TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszPath), lpszBuf, cchBuf);
+
+    if(SearchPathW(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL))
+        return TRUE;
+    return !!GetFullPathNameW(lpszPath, cchBuf, lpszBuf, NULL);
 }
 
 /*************************************************************************
@@ -3142,6 +3214,42 @@ LPWSTR WINAPI PathSkipRootW(LPCWSTR lpszPath)
 /*************************************************************************
  * PathCreateFromUrlA   [SHLWAPI.@]
  *
+ * See PathCreateFromUrlW
+ */
+HRESULT WINAPI PathCreateFromUrlA(LPCSTR pszUrl, LPSTR pszPath,
+                                  LPDWORD pcchPath, DWORD dwReserved)
+{
+    WCHAR bufW[MAX_PATH];
+    WCHAR *pathW = bufW;
+    UNICODE_STRING urlW;
+    HRESULT ret;
+    DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA;
+
+    if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl))
+        return E_INVALIDARG;
+    if((ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved)) == E_POINTER) {
+        pathW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
+        ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved);
+    }
+    if(ret == S_OK) {
+        RtlUnicodeToMultiByteSize(&lenA, pathW, lenW * sizeof(WCHAR));
+        if(*pcchPath > lenA) {
+            RtlUnicodeToMultiByteN(pszPath, *pcchPath - 1, &lenA, pathW, lenW * sizeof(WCHAR));
+            pszPath[lenA] = 0;
+            *pcchPath = lenA;
+        } else {
+            *pcchPath = lenA + 1;
+            ret = E_POINTER;
+        }
+    }
+    if(pathW != bufW) HeapFree(GetProcessHeap(), 0, pathW);
+    RtlFreeUnicodeString(&urlW);
+    return ret;
+}
+
+/*************************************************************************
+ * PathCreateFromUrlW   [SHLWAPI.@]
+ *
  * Create a path from a URL
  *
  * PARAMS
@@ -3154,74 +3262,66 @@ LPWSTR WINAPI PathSkipRootW(LPCWSTR lpszPath)
  *  Success: S_OK. lpszPath contains the URL in path format,
  *  Failure: An HRESULT error code such as E_INVALIDARG.
  */
-HRESULT WINAPI PathCreateFromUrlA(LPCSTR lpszUrl, LPSTR lpszPath,
-                                  LPDWORD pcchPath, DWORD dwFlags)
+HRESULT WINAPI PathCreateFromUrlW(LPCWSTR pszUrl, LPWSTR pszPath,
+                                  LPDWORD pcchPath, DWORD dwReserved)
 {
-  LPSTR pszPathPart;
-  TRACE("(%s,%p,%p,0x%08lx)\n", debugstr_a(lpszUrl), lpszPath, pcchPath, dwFlags);
+    static const WCHAR file_colon[] = { 'f','i','l','e',':',0 };
+    HRESULT hr;
+    DWORD nslashes = 0;
+    WCHAR *ptr;
 
-  if (!lpszUrl || !lpszPath || !pcchPath || !*pcchPath)
-    return E_INVALIDARG;
+    TRACE("(%s,%p,%p,0x%08lx)\n", debugstr_w(pszUrl), pszPath, pcchPath, dwReserved);
 
-  pszPathPart = StrChrA(lpszUrl, ':');
-  if ((((pszPathPart - lpszUrl) == 1) && isalpha(*lpszUrl)) ||
-         !lstrcmpA(lpszUrl, "file:"))
-  {
-    return UrlUnescapeA(pszPathPart, lpszPath, pcchPath, dwFlags);
-  }
-    /* extracts thing prior to : in pszURL and checks against:
-     *   https
-     *   shell
-     *   local
-     *   about  - if match returns E_INVALIDARG
-     */
+    if (!pszUrl || !pszPath || !pcchPath || !*pcchPath)
+        return E_INVALIDARG;
 
-  return E_INVALIDARG;
-}
 
-/*************************************************************************
- * PathCreateFromUrlW   [SHLWAPI.@]
- *
- * See PathCreateFromUrlA.
- */
-HRESULT WINAPI PathCreateFromUrlW(LPCWSTR lpszUrl, LPWSTR lpszPath,
-                                  LPDWORD pcchPath, DWORD dwFlags)
-{
-  static const WCHAR stemp[] = { 'f','i','l','e',':','/','/',0 };
-  LPWSTR pwszPathPart;
-  HRESULT hr;
+    if (strncmpW(pszUrl, file_colon, 5))
+        return E_INVALIDARG;
+    pszUrl += 5;
 
-  TRACE("(%s,%p,%p,0x%08lx)\n", debugstr_w(lpszUrl), lpszPath, pcchPath, dwFlags);
+    while(*pszUrl == '/' || *pszUrl == '\\') {
+        nslashes++;
+        pszUrl++;
+    }
 
-  if (!lpszUrl || !lpszPath || !pcchPath || !*pcchPath)
-    return E_INVALIDARG;
+    if(isalphaW(*pszUrl) && (pszUrl[1] == ':' || pszUrl[1] == '|') && (pszUrl[2] == '/' || pszUrl[2] == '\\'))
+        nslashes = 0;
 
-  /* Path of the form file://... */
-  if (!strncmpW(lpszUrl, stemp, 7))
-  {
-    lpszUrl += 7;
-  }
-  /* Path of the form file:... */
-  else if (!strncmpW(lpszUrl, stemp, 5))
-  {
-    lpszUrl += 5;
-  }
+    switch(nslashes) {
+    case 2:
+        pszUrl -= 2;
+        break;
+    case 0:
+        break;
+    default:
+        pszUrl -= 1;
+        break;
+    }
 
-  /* Ensure that path is of the form c:... or c|... */
-  if (lpszUrl[1] != ':' && lpszUrl[1] != '|' && isalphaW(*lpszUrl))
-    return E_INVALIDARG;
+    hr = UrlUnescapeW((LPWSTR)pszUrl, pszPath, pcchPath, 0);
+    if(hr != S_OK) return hr;
 
-  hr = UrlUnescapeW(lpszUrl, lpszPath, pcchPath, dwFlags);
-  if (lpszPath[1] == '|')
-    lpszPath[1] = ':';
+    for(ptr = pszPath; *ptr; ptr++)
+        if(*ptr == '/') *ptr = '\\';
 
-  for (pwszPathPart = lpszPath; *pwszPathPart; pwszPathPart++)
-    if (*pwszPathPart == '/')
-      *pwszPathPart = '\\';
+    while(*pszPath == '\\')
+        pszPath++;
+    if(isalphaW(*pszPath) && pszPath[1] == '|' && pszPath[2] == '\\') /* c|\ -> c:\ */
+        pszPath[1] = ':';
+
+    if(nslashes == 2 && (ptr = strchrW(pszPath, '\\'))) { /* \\host\c:\ -> \\hostc:\ */
+        ptr++;
+        if(isalphaW(*ptr) && (ptr[1] == ':' || ptr[1] == '|') && ptr[2] == '\\') {
+            memmove(ptr - 1, ptr, (strlenW(ptr) + 1) * sizeof(WCHAR));
+            (*pcchPath)--;
+        }
+    }
 
-  TRACE("Returning %s\n",debugstr_w(lpszPath));
+    TRACE("Returning %s\n",debugstr_w(pszPath));
 
-  return hr;
+    return hr;
 }
 
 /*************************************************************************
@@ -3269,10 +3369,10 @@ BOOL WINAPI PathRelativePathToA(LPSTR lpszPath, LPCSTR lpszFrom, DWORD dwAttrFro
     WCHAR szPath[MAX_PATH];
     WCHAR szFrom[MAX_PATH];
     WCHAR szTo[MAX_PATH];
-    MultiByteToWideChar(0,0,lpszFrom,-1,szFrom,MAX_PATH);
-    MultiByteToWideChar(0,0,lpszTo,-1,szTo,MAX_PATH);
+    MultiByteToWideChar(CP_ACP,0,lpszFrom,-1,szFrom,MAX_PATH);
+    MultiByteToWideChar(CP_ACP,0,lpszTo,-1,szTo,MAX_PATH);
     bRet = PathRelativePathToW(szPath,szFrom,dwAttrFrom,szTo,dwAttrTo);
-    WideCharToMultiByte(0,0,szPath,-1,lpszPath,MAX_PATH,0,0);
+    WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0);
   }
   return bRet;
 }
@@ -3298,8 +3398,8 @@ BOOL WINAPI PathRelativePathToW(LPWSTR lpszPath, LPCWSTR lpszFrom, DWORD dwAttrF
     return FALSE;
 
   *lpszPath = '\0';
-  strncpyW(szFrom, lpszFrom, MAX_PATH);
-  strncpyW(szTo, lpszTo, MAX_PATH);
+  lstrcpynW(szFrom, lpszFrom, MAX_PATH);
+  lstrcpynW(szTo, lpszTo, MAX_PATH);
 
   if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY))
     PathRemoveFileSpecW(szFrom);
@@ -3418,7 +3518,7 @@ VOID WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR lpszPath)
   TRACE("(%p,%8x,%s)\n",hDlg, id, debugstr_a(lpszPath));
 
   if (lpszPath)
-    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
+    MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
   else
     szPath[0] = '\0';
   PathSetDlgItemPathW(hDlg, id, szPath);
@@ -3443,7 +3543,7 @@ VOID WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR lpszPath)
     return;
 
   if (lpszPath)
-    strncpyW(path, lpszPath, sizeof(path));
+    lstrcpynW(path, lpszPath, sizeof(path) / sizeof(WCHAR));
   else
     path[0] = '\0';
 
@@ -3622,7 +3722,7 @@ BOOL WINAPI PathIsDirectoryEmptyA(LPCSTR lpszPath)
   if (lpszPath)
   {
     WCHAR szPath[MAX_PATH];
-    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
+    MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
     bRet = PathIsDirectoryEmptyW(szPath);
   }
   return bRet;
@@ -3647,7 +3747,7 @@ BOOL WINAPI PathIsDirectoryEmptyW(LPCWSTR lpszPath)
   if (!lpszPath || !PathIsDirectoryW(lpszPath))
       return FALSE;
 
-  strncpyW(szSearch, lpszPath, MAX_PATH);
+  lstrcpynW(szSearch, lpszPath, MAX_PATH);
   PathAddBackslashW(szSearch);
   dwLen = strlenW(szSearch);
   if (dwLen > MAX_PATH - 4)
@@ -3688,7 +3788,7 @@ BOOL WINAPI PathIsDirectoryEmptyW(LPCWSTR lpszPath)
  *  The match is made against the end of the suffix string, so for example:
  *  lpszSuffix="fooBAR" matches "BAR", but lpszSuffix="fooBARfoo" does not.
  */
-int WINAPI PathFindSuffixArrayA(LPCSTR lpszSuffix, LPCSTR *lppszArray, int dwCount)
+LPCSTR WINAPI PathFindSuffixArrayA(LPCSTR lpszSuffix, LPCSTR *lppszArray, int dwCount)
 {
   size_t dwLen;
   int dwRet = 0;
@@ -3705,13 +3805,13 @@ int WINAPI PathFindSuffixArrayA(LPCSTR lpszSuffix, LPCSTR *lppszArray, int dwCou
       if (dwCompareLen < dwLen)
       {
         if (!strcmp(lpszSuffix + dwLen - dwCompareLen, *lppszArray))
-          return dwRet; /* Found */
+          return *lppszArray; /* Found */
       }
       dwRet++;
       lppszArray++;
     }
   }
-  return 0;
+  return NULL;
 }
 
 /*************************************************************************
@@ -3719,7 +3819,7 @@ int WINAPI PathFindSuffixArrayA(LPCSTR lpszSuffix, LPCSTR *lppszArray, int dwCou
  *
  * See PathFindSuffixArrayA.
  */
-int WINAPI PathFindSuffixArrayW(LPCWSTR lpszSuffix, LPCWSTR *lppszArray, int dwCount)
+LPCWSTR WINAPI PathFindSuffixArrayW(LPCWSTR lpszSuffix, LPCWSTR *lppszArray, int dwCount)
 {
   size_t dwLen;
   int dwRet = 0;
@@ -3736,13 +3836,13 @@ int WINAPI PathFindSuffixArrayW(LPCWSTR lpszSuffix, LPCWSTR *lppszArray, int dwC
       if (dwCompareLen < dwLen)
       {
         if (!strcmpW(lpszSuffix + dwLen - dwCompareLen, *lppszArray))
-          return dwRet; /* Found */
+          return *lppszArray; /* Found */
       }
       dwRet++;
       lppszArray++;
     }
   }
-  return 0;
+  return NULL;
 }
 
 /*************************************************************************
@@ -3818,6 +3918,38 @@ VOID WINAPI PathUndecorateW(LPWSTR lpszPath)
   }
 }
 
+/*************************************************************************
+ * PathUnExpandEnvStringsA [SHLWAPI.@]
+ *
+ * Substitute folder names in a path with their corresponding environment
+ * strings.
+ *
+ * PARAMS
+ *  pszPath  [I] Buffer containing the path to unexpand.
+ *  pszBuf   [O] Buffer to receive the unexpanded path.
+ *  cchBuf   [I] Size of pszBuf in characters.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR pszPath, LPSTR pszBuf, UINT cchBuf)
+{
+    FIXME("(%s,%s,0x%08x)\n", debugstr_a(pszPath), debugstr_a(pszBuf), cchBuf);
+    return FALSE;
+}
+
+/*************************************************************************
+ * PathUnExpandEnvStringsW [SHLWAPI.@]
+ *
+ * Unicode version of PathUnExpandEnvStringsA.
+ */
+BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR pszPath, LPWSTR pszBuf, UINT cchBuf)
+{
+    FIXME("(%s,%s,0x%08x)\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf);
+    return FALSE;
+}
+
 /*************************************************************************
  * @     [SHLWAPI.440]
  *
@@ -3839,10 +3971,10 @@ HRESULT WINAPI SHGetWebFolderFilePathA(LPCSTR lpszFile, LPSTR lpszPath, DWORD dw
 
   TRACE("(%s,%p,%ld)\n", lpszFile, lpszPath, dwPathLen);
 
-  MultiByteToWideChar(0, 0, lpszFile, -1, szFile, MAX_PATH);
+  MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, szFile, MAX_PATH);
   szPath[0] = '\0';
   hRet = SHGetWebFolderFilePathW(szFile, szPath, dwPathLen);
-  WideCharToMultiByte(0, 0, szPath, -1, lpszPath, dwPathLen, 0, 0);
+  WideCharToMultiByte(CP_ACP, 0, szPath, -1, lpszPath, dwPathLen, 0, 0);
   return hRet;
 }
 
@@ -3897,3 +4029,111 @@ HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR lpszFile, LPWSTR lpszPath, DWORD
     return S_OK;
   return E_FAIL;
 }
+
+#define PATH_CHAR_CLASS_LETTER      0x00000001
+#define PATH_CHAR_CLASS_ASTERIX     0x00000002
+#define PATH_CHAR_CLASS_DOT         0x00000004
+#define PATH_CHAR_CLASS_BACKSLASH   0x00000008
+#define PATH_CHAR_CLASS_COLON       0x00000010
+#define PATH_CHAR_CLASS_SEMICOLON   0x00000020
+#define PATH_CHAR_CLASS_COMMA       0x00000040
+#define PATH_CHAR_CLASS_SPACE       0x00000080
+#define PATH_CHAR_CLASS_OTHER_VALID 0x00000100
+#define PATH_CHAR_CLASS_DOUBLEQUOTE 0x00000200
+
+#define PATH_CHAR_CLASS_INVALID     0x00000000
+#define PATH_CHAR_CLASS_ANY         0xffffffff
+
+static const DWORD SHELL_charclass[] =
+{
+    /* 0x00 */  PATH_CHAR_CLASS_INVALID,      /* 0x01 */  PATH_CHAR_CLASS_INVALID,
+    /* 0x02 */  PATH_CHAR_CLASS_INVALID,      /* 0x03 */  PATH_CHAR_CLASS_INVALID,
+    /* 0x04 */  PATH_CHAR_CLASS_INVALID,      /* 0x05 */  PATH_CHAR_CLASS_INVALID,
+    /* 0x06 */  PATH_CHAR_CLASS_INVALID,      /* 0x07 */  PATH_CHAR_CLASS_INVALID,
+    /* 0x08 */  PATH_CHAR_CLASS_INVALID,      /* 0x09 */  PATH_CHAR_CLASS_INVALID,
+    /* 0x0a */  PATH_CHAR_CLASS_INVALID,      /* 0x0b */  PATH_CHAR_CLASS_INVALID,
+    /* 0x0c */  PATH_CHAR_CLASS_INVALID,      /* 0x0d */  PATH_CHAR_CLASS_INVALID,
+    /* 0x0e */  PATH_CHAR_CLASS_INVALID,      /* 0x0f */  PATH_CHAR_CLASS_INVALID,
+    /* 0x10 */  PATH_CHAR_CLASS_INVALID,      /* 0x11 */  PATH_CHAR_CLASS_INVALID,
+    /* 0x12 */  PATH_CHAR_CLASS_INVALID,      /* 0x13 */  PATH_CHAR_CLASS_INVALID,
+    /* 0x14 */  PATH_CHAR_CLASS_INVALID,      /* 0x15 */  PATH_CHAR_CLASS_INVALID,
+    /* 0x16 */  PATH_CHAR_CLASS_INVALID,      /* 0x17 */  PATH_CHAR_CLASS_INVALID,
+    /* 0x18 */  PATH_CHAR_CLASS_INVALID,      /* 0x19 */  PATH_CHAR_CLASS_INVALID,
+    /* 0x1a */  PATH_CHAR_CLASS_INVALID,      /* 0x1b */  PATH_CHAR_CLASS_INVALID,
+    /* 0x1c */  PATH_CHAR_CLASS_INVALID,      /* 0x1d */  PATH_CHAR_CLASS_INVALID,
+    /* 0x1e */  PATH_CHAR_CLASS_INVALID,      /* 0x1f */  PATH_CHAR_CLASS_INVALID,
+    /* ' '  */  PATH_CHAR_CLASS_SPACE,        /* '!'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '"'  */  PATH_CHAR_CLASS_DOUBLEQUOTE,  /* '#'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '$'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '%'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '&'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '\'' */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '('  */  PATH_CHAR_CLASS_OTHER_VALID,  /* ')'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '*'  */  PATH_CHAR_CLASS_ASTERIX,      /* '+'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* ','  */  PATH_CHAR_CLASS_COMMA,        /* '-'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '.'  */  PATH_CHAR_CLASS_DOT,          /* '/'  */  PATH_CHAR_CLASS_INVALID,
+    /* '0'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '1'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '2'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '3'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '4'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '5'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '6'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '7'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '8'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '9'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* ':'  */  PATH_CHAR_CLASS_COLON,        /* ';'  */  PATH_CHAR_CLASS_SEMICOLON,
+    /* '<'  */  PATH_CHAR_CLASS_INVALID,      /* '='  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '>'  */  PATH_CHAR_CLASS_INVALID,      /* '?'  */  PATH_CHAR_CLASS_LETTER,
+    /* '@'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* 'A'  */  PATH_CHAR_CLASS_ANY,
+    /* 'B'  */  PATH_CHAR_CLASS_ANY,          /* 'C'  */  PATH_CHAR_CLASS_ANY,
+    /* 'D'  */  PATH_CHAR_CLASS_ANY,          /* 'E'  */  PATH_CHAR_CLASS_ANY,
+    /* 'F'  */  PATH_CHAR_CLASS_ANY,          /* 'G'  */  PATH_CHAR_CLASS_ANY,
+    /* 'H'  */  PATH_CHAR_CLASS_ANY,          /* 'I'  */  PATH_CHAR_CLASS_ANY,
+    /* 'J'  */  PATH_CHAR_CLASS_ANY,          /* 'K'  */  PATH_CHAR_CLASS_ANY,
+    /* 'L'  */  PATH_CHAR_CLASS_ANY,          /* 'M'  */  PATH_CHAR_CLASS_ANY,
+    /* 'N'  */  PATH_CHAR_CLASS_ANY,          /* 'O'  */  PATH_CHAR_CLASS_ANY,
+    /* 'P'  */  PATH_CHAR_CLASS_ANY,          /* 'Q'  */  PATH_CHAR_CLASS_ANY,
+    /* 'R'  */  PATH_CHAR_CLASS_ANY,          /* 'S'  */  PATH_CHAR_CLASS_ANY,
+    /* 'T'  */  PATH_CHAR_CLASS_ANY,          /* 'U'  */  PATH_CHAR_CLASS_ANY,
+    /* 'V'  */  PATH_CHAR_CLASS_ANY,          /* 'W'  */  PATH_CHAR_CLASS_ANY,
+    /* 'X'  */  PATH_CHAR_CLASS_ANY,          /* 'Y'  */  PATH_CHAR_CLASS_ANY,
+    /* 'Z'  */  PATH_CHAR_CLASS_ANY,          /* '['  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '\\' */  PATH_CHAR_CLASS_BACKSLASH,    /* ']'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '^'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '_'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '`'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* 'a'  */  PATH_CHAR_CLASS_ANY,
+    /* 'b'  */  PATH_CHAR_CLASS_ANY,          /* 'c'  */  PATH_CHAR_CLASS_ANY,
+    /* 'd'  */  PATH_CHAR_CLASS_ANY,          /* 'e'  */  PATH_CHAR_CLASS_ANY,
+    /* 'f'  */  PATH_CHAR_CLASS_ANY,          /* 'g'  */  PATH_CHAR_CLASS_ANY,
+    /* 'h'  */  PATH_CHAR_CLASS_ANY,          /* 'i'  */  PATH_CHAR_CLASS_ANY,
+    /* 'j'  */  PATH_CHAR_CLASS_ANY,          /* 'k'  */  PATH_CHAR_CLASS_ANY,
+    /* 'l'  */  PATH_CHAR_CLASS_ANY,          /* 'm'  */  PATH_CHAR_CLASS_ANY,
+    /* 'n'  */  PATH_CHAR_CLASS_ANY,          /* 'o'  */  PATH_CHAR_CLASS_ANY,
+    /* 'p'  */  PATH_CHAR_CLASS_ANY,          /* 'q'  */  PATH_CHAR_CLASS_ANY,
+    /* 'r'  */  PATH_CHAR_CLASS_ANY,          /* 's'  */  PATH_CHAR_CLASS_ANY,
+    /* 't'  */  PATH_CHAR_CLASS_ANY,          /* 'u'  */  PATH_CHAR_CLASS_ANY,
+    /* 'v'  */  PATH_CHAR_CLASS_ANY,          /* 'w'  */  PATH_CHAR_CLASS_ANY,
+    /* 'x'  */  PATH_CHAR_CLASS_ANY,          /* 'y'  */  PATH_CHAR_CLASS_ANY,
+    /* 'z'  */  PATH_CHAR_CLASS_ANY,          /* '{'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '|'  */  PATH_CHAR_CLASS_INVALID,      /* '}'  */  PATH_CHAR_CLASS_OTHER_VALID,
+    /* '~'  */  PATH_CHAR_CLASS_OTHER_VALID
+};
+
+/*************************************************************************
+ * @     [SHLWAPI.455]
+ *
+ * Check if an ASCII char is of a certain class
+ */
+BOOL WINAPI PathIsValidCharA( char c, DWORD class )
+{
+    if ((unsigned)c > 0x7e)
+        return class & PATH_CHAR_CLASS_OTHER_VALID;
+
+    return class & SHELL_charclass[(unsigned)c];
+}
+
+/*************************************************************************
+ * @     [SHLWAPI.456]
+ *
+ * Check if a Unicode char is of a certain class
+ */
+BOOL WINAPI PathIsValidCharW( WCHAR c, DWORD class )
+{
+    if (c > 0x7e)
+        return class & PATH_CHAR_CLASS_OTHER_VALID;
+
+    return class & SHELL_charclass[c];
+}