From: Vladislav Timonin timoninvlad@yandex.ru
--- dlls/comdlg32/navbar.c | 267 +++++++++++++++++++++++++++++++++++------ 1 file changed, 227 insertions(+), 40 deletions(-)
diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index 7a58366bdd8..ab8e96a8064 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -27,6 +27,7 @@ #include "shlwapi.h" #include "commoncontrols.h" #include "pathcch.h" +#include "knownfolders.h"
#include "wine/debug.h" #include "wine/list.h" @@ -41,6 +42,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(commdlg); #define IDC_OVERFLOW 205 #define IDC_NAVREFRESHGOTO 206
+static const KNOWNFOLDERID *ACCEPTED_KNOWN_FOLDERS[] = +{ + &FOLDERID_Desktop, + &FOLDERID_ComputerFolder, + &FOLDERID_RecycleBinFolder, + &FOLDERID_Documents, +}; + typedef struct { HWND parent_hwnd; HWND container_hwnd; @@ -118,17 +127,65 @@ static void remove_tooltip(NAVBAR_INFO *info, HWND window) SendMessageW(info->tooltip, TTM_DELTOOLW, 0, (LPARAM)&toolinfo); }
+static WCHAR *get_current_path(NAVBAR_INFO *info) +{ + struct crumb *crumb; + WCHAR *cur_path = NULL; + IShellFolder *desktop_sf; + SHGDNF shgdn = SHGDN_FORPARSING; + STRRET strret; + HRESULT hr; + INT i; + + crumb = LIST_ENTRY(list_tail(&info->crumbs), struct crumb, entry); + if (!crumb) + return NULL; + + hr = SHGetDesktopFolder(&desktop_sf); + if (FAILED(hr)) + return NULL; + + /* check if current path is one of the known folders */ + /* and return known folder name instead if it is */ + for (i = 0; i < ARRAY_SIZE(ACCEPTED_KNOWN_FOLDERS); i++) + { + ITEMIDLIST *known_folder_pidl = NULL; + BOOL is_known_folder = FALSE; + + hr = SHGetKnownFolderIDList(ACCEPTED_KNOWN_FOLDERS[i], 0, NULL, &known_folder_pidl); + if (FAILED(hr)) + continue; + + is_known_folder = ILIsEqual(crumb->pidl, known_folder_pidl); + ILFree(known_folder_pidl); + + if (is_known_folder) + { + shgdn = SHGDN_NORMAL; + break; + } + } + + hr = IShellFolder_GetDisplayNameOf(desktop_sf, crumb->pidl, shgdn, &strret); + if (SUCCEEDED(hr)) + hr = StrRetToStrW(&strret, crumb->pidl, &cur_path); + + IShellFolder_Release(desktop_sf); + + return cur_path; +} + static HDWP NAVBAR_DoLayout(NAVBAR_INFO *info, HDWP hdwp);
static void NAVBAR_PATHEDIT_SetCurrentPath(NAVBAR_INFO *info) { - struct crumb *crumb; - WCHAR cur_path[MAX_PATH]; + WCHAR *cur_path = get_current_path(info); + if (!cur_path) + return;
- crumb = LIST_ENTRY(list_tail(&info->crumbs), struct crumb, entry); - SHGetPathFromIDListW(crumb->pidl, cur_path); SetWindowTextW(info->pathedit_hwnd, cur_path); SendMessageW(info->pathedit_hwnd, EM_SETSEL, 0, -1); /* select all */ + CoTaskMemFree(cur_path); }
static void NAVBAR_PATHEDIT_Edit(NAVBAR_INFO *info) @@ -195,36 +252,98 @@ static LRESULT NAVBAR_PATHEDIT_KillFocus(HWND hwnd, NAVBAR_INFO *info, UINT msg, return DefSubclassProc(hwnd, msg, wparam, lparam); }
-static void NAVBAR_PATHEDIT_GoTo(NAVBAR_INFO *info) +static ITEMIDLIST *NAVBAR_PATHEDIT_ParseUnixPath(WCHAR *text) { - WCHAR *text = NULL, *expanded = NULL, *canonicalized = NULL; - INT text_len = 0; - DWORD expanded_len; + ITEMIDLIST *pidl = NULL; + WCHAR *dos_path = NULL; + CHAR *unix_path = NULL; + INT unix_path_len; + + unix_path_len = WideCharToMultiByte(CP_UNIXCP, 0, text, -1, NULL, 0, NULL, NULL); + unix_path = HeapAlloc(GetProcessHeap(), 0, unix_path_len * sizeof(WCHAR)); + if (!unix_path) + return NULL; + + unix_path_len = WideCharToMultiByte(CP_UNIXCP, 0, text, -1, unix_path, unix_path_len, NULL, NULL); + if (!unix_path_len) + return NULL; + + dos_path = wine_get_dos_file_name(unix_path); + HeapFree(GetProcessHeap(), 0, unix_path); + + TRACE("%s\n", debugstr_w(dos_path)); + + if (!PathFileExistsW(dos_path)) + return NULL; + + SHILCreateFromPath(dos_path, &pidl, 0); + + return pidl; +} + +static ITEMIDLIST *NAVBAR_PATHEDIT_ParseKnownFolder(WCHAR *text) +{ + IShellFolder *desktop = NULL; ITEMIDLIST *pidl = NULL; HRESULT hr; + INT i;
- text_len = GetWindowTextLengthW(info->pathedit_hwnd); - if (!text_len) - goto exit; + hr = SHGetDesktopFolder(&desktop); + if (FAILED(hr)) + return NULL;
- text = HeapAlloc(GetProcessHeap(), 0, (text_len + 1) * sizeof(WCHAR)); - if (!text) - goto exit; + for (i = 0; i < ARRAY_SIZE(ACCEPTED_KNOWN_FOLDERS); i++) + { + ITEMIDLIST *known_folder_pidl = NULL; + STRRET strret;
- if (!GetWindowTextW(info->pathedit_hwnd, text, text_len + 1)) - goto cleanup; + hr = SHGetKnownFolderIDList(ACCEPTED_KNOWN_FOLDERS[i], 0, NULL, &known_folder_pidl); + if (FAILED(hr)) + continue;
- TRACE("text %s\n", debugstr_w(text)); + hr = IShellFolder_GetDisplayNameOf(desktop, known_folder_pidl, SHGDN_NORMAL, &strret); + if (SUCCEEDED(hr)) + { + WCHAR *name;
- StrTrimW(text, L" "); + hr = StrRetToStrW(&strret, known_folder_pidl, &name); + if (SUCCEEDED(hr)) + { + BOOL is_known_folder = !lstrcmpiW(name, text); + CoTaskMemFree(name); + + if (is_known_folder) + { + TRACE("%s\n", debugstr_guid(ACCEPTED_KNOWN_FOLDERS[i])); + pidl = known_folder_pidl; + break; + } + } + } + + ILFree(known_folder_pidl); + } + + IShellFolder_Release(desktop); + + return pidl; +} + +static ITEMIDLIST *NAVBAR_PATHEDIT_ParseWindowsPath(NAVBAR_INFO *info, WCHAR *text) +{ + WCHAR *expanded = NULL, *full = NULL; + DWORD expanded_len; + ITEMIDLIST *pidl = NULL; + IShellFolder *desktop = NULL; + HRESULT hr = S_OK;
expanded_len = ExpandEnvironmentStringsW(text, NULL, 0); if (!expanded_len) - goto cleanup; + return NULL;
expanded = HeapAlloc(GetProcessHeap(), 0, expanded_len * sizeof(WCHAR)); if (!expanded) - goto cleanup; + return NULL;
expanded_len = ExpandEnvironmentStringsW(text, expanded, expanded_len); if (!expanded_len) @@ -232,38 +351,106 @@ static void NAVBAR_PATHEDIT_GoTo(NAVBAR_INFO *info)
TRACE("expanded %s\n", debugstr_w(expanded));
- hr = PathAllocCanonicalize(expanded, PATHCCH_ALLOW_LONG_PATHS, &canonicalized); - if (FAILED(hr)) + if (PathIsRelativeW(expanded)) + { + WCHAR *current = get_current_path(info); + + if (!PathIsRelativeW(current)) + { + hr = PathAllocCombine(current, expanded, PATHCCH_ALLOW_LONG_PATHS, &full); + TRACE("current %s relative %s combined %s\n", debugstr_w(current), debugstr_w(expanded), debugstr_w(full)); + } + + CoTaskMemFree(current); + if (FAILED(hr)) + goto cleanup; + } + else + { + hr = PathAllocCanonicalize(expanded, PATHCCH_ALLOW_LONG_PATHS, &full); + if (FAILED(hr)) + goto cleanup; + + TRACE("canonicalized %s\n", debugstr_w(full)); + } + + if (!PathFileExistsW(full)) + return NULL; + + SHILCreateFromPath(full, &pidl, 0); + +cleanup: + if (expanded) + HeapFree(GetProcessHeap(), 0, expanded); + if (full) + LocalFree(full); + if (desktop) + IShellFolder_Release(desktop); + + return pidl; +} + +static void NAVBAR_PATHEDIT_GoTo(NAVBAR_INFO *info) +{ + WCHAR *text = NULL; + INT text_len = 0; + ITEMIDLIST *pidl = NULL; + + text_len = GetWindowTextLengthW(info->pathedit_hwnd); + if (!text_len) + goto exit; + + text = HeapAlloc(GetProcessHeap(), 0, (text_len + 1) * sizeof(WCHAR)); + if (!text) + goto exit; + + if (!GetWindowTextW(info->pathedit_hwnd, text, text_len + 1)) goto cleanup;
- TRACE("canonicalized %s\n", debugstr_w(canonicalized)); + StrTrimW(text, L" ");
- /* check if we have a valid path */ - if (GetFileAttributesW(canonicalized) == INVALID_FILE_ATTRIBUTES) + TRACE("text %s\n", debugstr_w(text)); + + if (StrCmpW(text, L"..") == 0 || + StrCmpW(text, L"../") == 0 || + StrCmpW(text, L"..\") == 0) + { + struct crumb *last_crumb = LIST_ENTRY(list_tail(&info->crumbs), struct crumb, entry), + *parent_crumb = NULL; + + if (last_crumb && last_crumb->entry.prev != &info->crumbs) + parent_crumb = LIST_ENTRY(last_crumb->entry.prev, struct crumb, entry); + + if (parent_crumb) + pidl = ILClone(parent_crumb->pidl); + } + else if (text[0] == '/') + pidl = NAVBAR_PATHEDIT_ParseUnixPath(text); + else + { + pidl = NAVBAR_PATHEDIT_ParseKnownFolder(text); + if (!pidl) + pidl = NAVBAR_PATHEDIT_ParseWindowsPath(info, text); + } + + TRACE("pidl %p\n", pidl); + + if (pidl) + { + SendMessageW(info->parent_hwnd, NBN_NAVPIDL, 0, (LPARAM)pidl); + ILFree(pidl); + } + else { WCHAR spec[MAX_PATH + 128] = {0}, caption[MAX_PATH + 128] = {0}; LoadStringW(COMDLG32_hInstance, IDS_WINE_CANT_FIND_ADDRESS, spec, ARRAY_SIZE(spec)); wsprintfW(caption, spec, text); MessageBoxW(info->parent_hwnd, caption, NULL, MB_ICONERROR | MB_OK); - goto cleanup; }
- hr = SHILCreateFromPath(canonicalized, &pidl, 0); - if (FAILED(hr)) - goto cleanup; - - TRACE("pidl %p\n", pidl); - - SendMessageW(info->parent_hwnd, NBN_NAVPIDL, 0, (LPARAM)pidl); - ILFree(pidl); cleanup: - if (text) - HeapFree(GetProcessHeap(), 0, text); - if (expanded) - HeapFree(GetProcessHeap(), 0, expanded); - if (canonicalized) - HeapFree(GetProcessHeap(), 0, canonicalized); + HeapFree(GetProcessHeap(), 0, text); exit: NAVBAR_PATHEDIT_Dismiss(info); }