From 9e355fcfa454ba113c2ab4fbbb0d3152138159fd Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sat, 11 Feb 2023 12:06:09 +0900 Subject: [PATCH] ShellExtension: Fix the problem that the WinMerge menu does not appear when right-clicking on a non-item area in Explorer. --- ShellExtension/WinMergeContextMenu/dllmain.cpp | 134 ++++++++----------------- 1 file changed, 43 insertions(+), 91 deletions(-) diff --git a/ShellExtension/WinMergeContextMenu/dllmain.cpp b/ShellExtension/WinMergeContextMenu/dllmain.cpp index 33915cb5e..f4a6914f0 100644 --- a/ShellExtension/WinMergeContextMenu/dllmain.cpp +++ b/ShellExtension/WinMergeContextMenu/dllmain.cpp @@ -108,94 +108,38 @@ public: protected: // code from https://github.com/microsoft/terminal/blob/main/src/cascadia/ShellExtension/OpenTerminalHere.cpp - std::wstring _GetPathFromExplorer() const - { - std::wstring path; - HRESULT hr = NOERROR; - - auto hwnd = ::GetForegroundWindow(); - if (hwnd == nullptr) - { - return path; - } - - TCHAR szName[MAX_PATH] = { 0 }; - ::GetClassName(hwnd, szName, MAX_PATH); - if (0 == StrCmp(szName, L"WorkerW") || - 0 == StrCmp(szName, L"Progman")) - { - //special folder: desktop - hr = ::SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, szName); - if (FAILED(hr)) - { - return path; - } - - path = szName; - return path; - } - - if (0 != StrCmp(szName, L"CabinetWClass")) - { - return path; - } - - ComPtr shell; - hr = CoCreateInstance(CLSID_ShellWindows, nullptr, CLSCTX_ALL, IID_IShellWindows, &shell); - if (FAILED(hr) || shell == nullptr) - { - return path; - } - - ComPtr disp; - wil::unique_variant variant; - variant.vt = VT_I4; - - ComPtr browser; - // look for correct explorer window - for (variant.intVal = 0; - shell->Item(variant, &disp) == S_OK; - variant.intVal++) - { - ComPtr tmp; - if (FAILED(disp->QueryInterface(&tmp))) - { - disp = nullptr; // get rid of DEBUG non-nullptr warning - continue; - } - - HWND tmpHWND = NULL; - hr = tmp->get_HWND(reinterpret_cast(&tmpHWND)); - if (hwnd == tmpHWND) - { - browser = tmp; - disp = nullptr; // get rid of DEBUG non-nullptr warning - break; //found - } - - disp = nullptr; // get rid of DEBUG non-nullptr warning - } - - if (browser != nullptr) - { - wil::unique_bstr url; - hr = browser->get_LocationURL(&url); - if (FAILED(hr)) - { - return path; - } - - std::wstring sUrl(url.get(), SysStringLen(url.get())); - DWORD size = MAX_PATH; - hr = ::PathCreateFromUrl(sUrl.c_str(), szName, &size, NULL); - if (SUCCEEDED(hr)) - { - path = szName; - } - } - - return path; - } + HRESULT GetBestLocationFromSelectionOrSite(IShellItemArray* psiArray, IShellItem** location) const noexcept + { + ComPtr psi; + if (psiArray) + { + DWORD count{}; + RETURN_IF_FAILED(psiArray->GetCount(&count)); + if (count) // Sometimes we get an array with a count of 0. Fall back to the site chain. + { + RETURN_IF_FAILED(psiArray->GetItemAt(0, &psi)); + } + } + + if (!psi) + { + RETURN_IF_FAILED(GetLocationFromSite(&psi)); + } + + RETURN_HR_IF(S_FALSE, !psi); + RETURN_IF_FAILED(psi.CopyTo(location)); + return S_OK; + } + + HRESULT GetLocationFromSite(IShellItem** location) const noexcept + { + ComPtr serviceProvider; + RETURN_IF_FAILED(m_site.As(&serviceProvider)); + ComPtr folderView; + RETURN_IF_FAILED(serviceProvider->QueryService(SID_SFolderView, &folderView)); + RETURN_IF_FAILED(folderView->GetFolder(IID_PPV_ARGS(location))); + return S_OK; + } std::vector GetPaths(_In_opt_ IShellItemArray* selection) { @@ -203,9 +147,17 @@ protected: DWORD dwNumItems = 0; if (!selection) { - std::wstring path = _GetPathFromExplorer(); - if (!path.empty()) - paths.push_back(path); + ComPtr psi; + if (SUCCEEDED(GetBestLocationFromSelectionOrSite(selection, &psi))) + { + wil::unique_cotaskmem_string pszFilePath; + if (SUCCEEDED(psi->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath))) + { + std::wstring path = pszFilePath.get(); + if (!path.empty()) + paths.push_back(path); + } + } } else { -- 2.11.0