diff --git a/dlls/shell32/shell32.spec b/dlls/shell32/shell32.spec index 6c0d7d8f591..e054db3d752 100644 --- a/dlls/shell32/shell32.spec +++ b/dlls/shell32/shell32.spec @@ -344,6 +344,8 @@ @ stdcall SHGetFileInfoW(ptr long ptr long long) @ stdcall SHGetFolderLocation(long long long long ptr) @ stdcall SHGetFolderPathA(long long long long ptr) +@ stdcall SHGetFolderPathAndSubDirA(long long long long str ptr) +@ stdcall SHGetFolderPathAndSubDirW(long long long long wstr ptr) @ stdcall SHGetFolderPathW(long long long long ptr) @ stub SHGetFreeDiskSpace @ stub SHGetIconOverlayIndexA diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index c4ae6886898..abbaf1927df 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -1674,6 +1674,70 @@ HRESULT WINAPI SHGetFolderPathW( HANDLE hToken, /* [I] access token */ DWORD dwFlags, /* [I] which path to return */ LPWSTR pszPath) /* [O] converted path */ +{ + HRESULT hr = SHGetFolderPathAndSubDirW(hwndOwner, nFolder, hToken, dwFlags, NULL, pszPath); + if(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) + hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + return hr; +} + +HRESULT WINAPI SHGetFolderPathAndSubDirA( + HWND hwndOwner, /* [I] owner window */ + int nFolder, /* [I] CSIDL identifying the folder */ + HANDLE hToken, /* [I] access token */ + DWORD dwFlags, /* [I] which path to return */ + LPCSTR pszSubPath, /* [I] sub directory of the specified folder */ + LPSTR pszPath) /* [O] converted path */ +{ + int length; + HRESULT hr = S_OK; + LPWSTR pszSubPathW = NULL; + LPWSTR pszPathW = NULL; + TRACE("%08x,%08x,%s\n",nFolder, dwFlags, debugstr_w(pszSubPathW)); + + if(pszPath) { + pszPathW = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR)); + if(!pszPathW) { + hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + WARN("Failed to allocate %u bytes of memory\n", MAX_PATH * sizeof(WCHAR)); + goto cleanup; + } + } + TRACE("%08x,%08x,%s\n",nFolder, dwFlags, debugstr_w(pszSubPathW)); + + /* SHGetFolderPathAndSubDirW does not distinguish if pszSubPath isn't + * set (null), or an empty string.therefore call it without the parameter set + * if pszSubPath is an empty string + */ + if (pszSubPath && pszSubPath[0]) { + length = MultiByteToWideChar(CP_ACP, 0, pszSubPath, -1, NULL, 0); + pszSubPathW = HeapAlloc(GetProcessHeap(), 0, length * sizeof(WCHAR)); + if(!pszSubPathW) { + hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + WARN("Failed to allocate %u bytes of memory\n", length * sizeof(WCHAR)); + goto cleanup; + } + MultiByteToWideChar(CP_ACP, 0, pszSubPath, -1, pszSubPathW, length); + } + + hr = SHGetFolderPathAndSubDirW(hwndOwner, nFolder, hToken, dwFlags, pszSubPathW, pszPathW); + + if (SUCCEEDED(hr) && pszPath) + WideCharToMultiByte(CP_ACP, 0, pszPathW, -1, pszPath, MAX_PATH, NULL, NULL); + +cleanup: + HeapFree(GetProcessHeap(), 0, pszPathW); + HeapFree(GetProcessHeap(), 0, pszSubPathW); + return hr; +} + +HRESULT WINAPI SHGetFolderPathAndSubDirW( + HWND hwndOwner, /* [I] owner window */ + int nFolder, /* [I] CSIDL identifying the folder */ + HANDLE hToken, /* [I] access token */ + DWORD dwFlags, /* [I] which path to return */ + LPCWSTR pszSubPath,/* [I] sub directory of the specified folder */ + LPWSTR pszPath) /* [O] converted path */ { HRESULT hr; WCHAR szBuildPath[MAX_PATH], szTemp[MAX_PATH]; @@ -1681,15 +1745,18 @@ HRESULT WINAPI SHGetFolderPathW( CSIDL_Type type; int ret; - TRACE("%p,%p,nFolder=0x%04x\n", hwndOwner,pszPath,nFolder); + TRACE("%p,%p,nFolder=0x%04x,%s\n", hwndOwner,pszPath,nFolder,debugstr_w(pszSubPath)); /* Windows always NULL-terminates the resulting path regardless of success * or failure, so do so first */ if (pszPath) *pszPath = '\0'; + if (folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0])) return E_INVALIDARG; + if ((SHGFP_TYPE_CURRENT != dwFlags) && (SHGFP_TYPE_DEFAULT != dwFlags)) + return E_INVALIDARG; szTemp[0] = 0; type = CSIDL_Data[folder].type; switch (type) @@ -1742,12 +1809,23 @@ HRESULT WINAPI SHGetFolderPathW( hr = _SHExpandEnvironmentStrings(szTemp, szBuildPath); else strcpyW(szBuildPath, szTemp); + + if (FAILED(hr)) goto end; + + if(pszSubPath) { + /* make sure the new path does not exceed th bufferlength + * rememebr to backslash and the termination */ + if(MAX_PATH < (lstrlenW(szBuildPath) + lstrlenW(pszSubPath) + 2)) { + hr = HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE); + goto end; + } + PathAppendW(szBuildPath, pszSubPath); + PathRemoveBackslashW(szBuildPath); + } /* Copy the path if it's available before we might return */ if (SUCCEEDED(hr) && pszPath) strcpyW(pszPath, szBuildPath); - if (FAILED(hr)) goto end; - /* if we don't care about existing directories we are ready */ if(nFolder & CSIDL_FLAG_DONT_VERIFY) goto end; @@ -1758,7 +1836,7 @@ HRESULT WINAPI SHGetFolderPathW( */ if (!(nFolder & CSIDL_FLAG_CREATE)) { - hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); goto end; } diff --git a/include/shlobj.h b/include/shlobj.h index 8dbccb75252..159e85a76d6 100644 --- a/include/shlobj.h +++ b/include/shlobj.h @@ -54,6 +54,9 @@ DWORD WINAPI SHFormatDrive(HWND,UINT,UINT,UINT); void WINAPI SHFree(LPVOID); BOOL WINAPI GetFileNameFromBrowse(HWND,LPSTR,DWORD,LPCSTR,LPCSTR,LPCSTR,LPCSTR); HRESULT WINAPI SHGetInstanceExplorer(IUnknown**); +HRESULT WINAPI SHGetFolderPathAndSubDirA(HWND,int,HANDLE,DWORD,LPCSTR,LPSTR); +HRESULT WINAPI SHGetFolderPathAndSubDirW(HWND,int,HANDLE,DWORD,LPCWSTR,LPWSTR); +#define SHGetFolderPathAndSubDir WINELIB_NAME_AW(SHGetFolderPathAndSubDir); BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST,LPSTR); BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST,LPWSTR); #define SHGetPathFromIDList WINELIB_NAME_AW(SHGetPathFromIDList)