diff options
Diffstat (limited to 'Src/Plugins/Library/ml_local/FolderBrowseEx.cpp')
-rw-r--r-- | Src/Plugins/Library/ml_local/FolderBrowseEx.cpp | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_local/FolderBrowseEx.cpp b/Src/Plugins/Library/ml_local/FolderBrowseEx.cpp new file mode 100644 index 00000000..2c1b0de1 --- /dev/null +++ b/Src/Plugins/Library/ml_local/FolderBrowseEx.cpp @@ -0,0 +1,239 @@ +#include "main.h" +#include "./folderbrowseex.h" +#include "../nu/CGlobalAtom.h" +#include <shobjidl.h> +#include "../replicant/nu/AutoWide.h" + +static CGlobalAtom CLSPROP(L"FBEXDLG"); + +#ifdef _WIN64 +#define LONGPTR_CAST LONG_PTR +#else +#define LONGPTR_CAST LONG +#endif + +#define PATHTYPE_PIDL FALSE +#define PATHTYPE_STRING TRUE + +BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam) +{ + wchar_t cl[32] = {0}; + GetClassName(hwnd, cl, ARRAYSIZE(cl)); + if (!lstrcmpi(cl, WC_TREEVIEW)) + { + PostMessage(hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection(hwnd)); + return FALSE; + } + + return TRUE; +} + +static int WINAPI BrowseCallback_Helper(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + FolderBrowseEx *lpfbex = reinterpret_cast<FolderBrowseEx*>(lpData); + if (!lpfbex) return 0; + + switch (uMsg) + { + case BFFM_INITIALIZED: + lpfbex->hwnd = hwnd; + if(SetPropW(hwnd, CLSPROP, (void*)lpData)) + { + lpfbex->oldProc = (LONG_PTR) ((IsWindowUnicode(hwnd)) ? SetWindowLongPtrW(hwnd, DWLP_DLGPROC, (LONGPTR_CAST)WindowProc_Helper) : SetWindowLongPtrA(hwnd, DWLP_DLGPROC, (LONGPTR_CAST)WindowProc_Helper)); + if (NULL == lpfbex->oldProc) RemovePropW(hwnd, CLSPROP); + } + + // this is not nice but it fixes the selection not working correctly on all OSes + EnumChildWindows(hwnd, browseEnumProc, 0); + break; + } + return lpfbex->BrowseCallback(uMsg, lParam); +} + +static LRESULT WINAPI WindowProc_Helper(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + FolderBrowseEx *lpfbex = static_cast<FolderBrowseEx*>(GetPropW(hwnd, CLSPROP)); + if (!lpfbex) return 0; + + switch(uMsg) + { + case WM_NCDESTROY: + lpfbex->DialogProc(uMsg, wParam, lParam); + if (IsWindowUnicode(hwnd)) SetWindowLongPtrW(hwnd, DWLP_DLGPROC, (LONGPTR_CAST)lpfbex->oldProc); + else SetWindowLongPtrA(hwnd, DWLP_DLGPROC, (LONGPTR_CAST)lpfbex->oldProc); + RemovePropW(hwnd, CLSPROP); + lpfbex->oldProc = NULL; + lpfbex->hwnd = NULL; + return 0; + } + return lpfbex->DialogProc(uMsg, wParam, lParam); +} + +static void Initialize(FolderBrowseEx *lpfbx, LPCITEMIDLIST pidlRoot, UINT ulFlags, LPCWSTR lpszCaption, LPCWSTR lpszTitle) +{ + lpfbx->pidlRoot = pidlRoot; + lpfbx->ulFlags = ulFlags; + + lpfbx->lpszCaption = NULL; + lpfbx->lpszTitle = NULL; + lpfbx->image = -1; + lpfbx->pidl = NULL; + lpfbx->hwnd = NULL; + lpfbx->oldProc = NULL; + + CoInitialize(NULL); + + lpfbx->pathExpanded.empty = TRUE; + lpfbx->pathSelection.empty = TRUE; + + if (lpszCaption) lpfbx->SetCaption(lpszCaption); + if (lpszTitle) lpfbx->SetTitle(lpszTitle); +} + +FolderBrowseEx::FolderBrowseEx(LPCITEMIDLIST pidlRoot, UINT ulFlags, LPCWSTR lpszCaption, LPCWSTR lpszTitle) +{ + Initialize(this, pidlRoot, ulFlags, lpszCaption, lpszTitle); +} + +FolderBrowseEx::FolderBrowseEx(UINT ulFlags, LPCWSTR lpszCaption, LPCWSTR lpszTitle) +{ + Initialize(this, NULL, ulFlags, lpszCaption, lpszTitle); +} + +FolderBrowseEx::FolderBrowseEx(UINT ulFlags, LPCWSTR lpszTitle) +{ + Initialize(this, NULL, ulFlags, L"", lpszTitle); +} + +FolderBrowseEx::FolderBrowseEx(void) +{ + Initialize(this, NULL, 0, L"", L""); +} + +FolderBrowseEx::~FolderBrowseEx(void) +{ + if (pidl) CoTaskMemFree(pidl); + if (lpszTitle) free(lpszTitle); + if (lpszCaption) free(lpszCaption); + CoUninitialize(); +} + +HRESULT FolderBrowseEx::ParseDisplayName(LPCWSTR lpszPath, IBindCtx *pbc, LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut) +{ + IShellFolder *isf = NULL; + HRESULT result; + SFGAOF attrib; + + if (NOERROR != (result = SHGetDesktopFolder(&isf))) return result; + attrib = sfgaoIn; + result = isf->ParseDisplayName(NULL, pbc, (LPWSTR)lpszPath, NULL, ppidl, &attrib); + isf->Release(); + + if (S_OK != result) *ppidl = NULL; + else if (psfgaoOut) *psfgaoOut = attrib; + return result; +} + +void FolderBrowseEx::SetExpanded(LPCITEMIDLIST pidlExpand) +{ + pathExpanded.empty = FALSE; + pathExpanded.type = PATHTYPE_PIDL; + pathExpanded.value = (void*)pidlExpand; + if (hwnd) SendMessage(BFFM_SETEXPANDED, pathExpanded.type, (LPARAM)pathExpanded.value); +} + +void FolderBrowseEx::SetExpanded(LPCWSTR lpszExpand) +{ + pathExpanded.empty = FALSE; + pathExpanded.type = PATHTYPE_STRING; + pathExpanded.value = (void*)lpszExpand; + if (hwnd) SendMessage(BFFM_SETEXPANDED, pathExpanded.type, (LPARAM)pathExpanded.value); +} + +void FolderBrowseEx::SetSelection(LPCITEMIDLIST pidlSelect) +{ + pathSelection.empty = FALSE; + pathSelection.type = PATHTYPE_PIDL; + pathSelection.value = (void*)pidlSelect; + if (hwnd) SendMessage(BFFM_SETSELECTIONW, pathSelection.type, (LPARAM)pathSelection.value); +} + +void FolderBrowseEx::SetSelection(LPCWSTR lpszSelect) +{ + pathSelection.empty = FALSE; + pathSelection.type = PATHTYPE_STRING; + pathSelection.value = (void*)lpszSelect; + if (hwnd) SendMessage(BFFM_SETSELECTIONW, pathSelection.type, (LPARAM)pathSelection.value); +} + +void FolderBrowseEx::SetCaption(LPCWSTR lpszCaption) +{ + if (this->lpszCaption) free(this->lpszCaption); + this->lpszCaption = _wcsdup((lpszCaption) ? lpszCaption : L""); + if (hwnd) SetWindowText(lpszCaption); +} + +void FolderBrowseEx::SetTitle(LPCWSTR lpszTitle) +{ + if (this->lpszTitle) free(this->lpszTitle); + this->lpszTitle = _wcsdup((lpszTitle) ? lpszTitle : L""); +} + +LPITEMIDLIST FolderBrowseEx::Browse(HWND hwndOwner) +{ + BROWSEINFOW bi = {0}; + bi.hwndOwner = hwndOwner; + bi.pidlRoot = pidlRoot; + bi.pszDisplayName = pszDisplayName; + bi.lpszTitle = lpszTitle; + bi.ulFlags = ulFlags; + bi.lpfn = BrowseCallback_Helper; + bi.lParam = (LPARAM)this; + + pidl = SHBrowseForFolderW(&bi); + if (pidl) OnSelectionDone(pidl); + + image = (pidl) ? bi.iImage : -1; + + return pidl; +} + +INT FolderBrowseEx::BrowseCallback(UINT uMsg, LPARAM lParam) +{ + switch(uMsg) + { + case BFFM_INITIALIZED: OnInitialized(); break; + case BFFM_IUNKNOWN: OnIUnknown((IUnknown*)lParam); break; + case BFFM_SELCHANGED: OnSelectionChanged((LPCITEMIDLIST)lParam); break; + case BFFM_VALIDATEFAILEDA: return OnValidateFailed(AutoWide((LPCSTR)lParam)); + case BFFM_VALIDATEFAILEDW: return OnValidateFailed((LPCWSTR)lParam); + } + return 0; +} + +void FolderBrowseEx::OnInitialized(void) +{ + if (!pathSelection.empty) SendMessage(BFFM_SETSELECTIONW, pathSelection.type, (LPARAM)pathSelection.value); + if (!pathExpanded.empty) SendMessage(BFFM_SETEXPANDED, pathExpanded.type, (LPARAM)pathExpanded.value); + SetWindowText(lpszCaption); +} + +void FolderBrowseEx::OnSelectionChanged(LPCITEMIDLIST pidl) +{ +} + +INT_PTR FolderBrowseEx::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + return CallWindowProc(uMsg, wParam, lParam); +} + +INT_PTR FolderBrowseEx::CallWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + return (IsWindowUnicode(hwnd)) ? ::CallWindowProcW((WNDPROC)oldProc, hwnd, uMsg, wParam, lParam) + : ::CallWindowProcA((WNDPROC)oldProc, hwnd, uMsg, wParam, lParam); +} + +void FolderBrowseEx::SetDialogResult(LRESULT result) +{ + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG)(LONG_PTR)result); +}
\ No newline at end of file |