From e3946d5d474e61cc683df81a74b46bca0238cb54 Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Mon, 23 May 2022 21:52:31 +0900 Subject: [PATCH] WinMergeContextMenu: Fix the problem that the WinMerge icon is not correctly displayed on the taskbar when WinMerge is started from the Windows 11 context menu. I referred to the following URL - https://gitlab.com/tortoisegit/tortoisegit/-/merge_requests/187 - https://devblogs.microsoft.com/oldnewthing/20131118-00/?p=2643 - https://devblogs.microsoft.com/oldnewthing/20130318-00/?p=4933 --- ShellExtension/Common/WinMergeContextMenu.cpp | 111 ++++++++++++++++++++++++- ShellExtension/Common/WinMergeContextMenu.h | 3 + ShellExtension/WinMergeContextMenu/dllmain.cpp | 7 +- 3 files changed, 118 insertions(+), 3 deletions(-) diff --git a/ShellExtension/Common/WinMergeContextMenu.cpp b/ShellExtension/Common/WinMergeContextMenu.cpp index a0603fdfd..6286f1481 100644 --- a/ShellExtension/Common/WinMergeContextMenu.cpp +++ b/ShellExtension/Common/WinMergeContextMenu.cpp @@ -3,6 +3,11 @@ #include "LanguageSelect.h" #include "../ShellExtension/Resource.h" #include +#include +#include +#include +#include +#include /// Max. filecount to select static const int MaxFileCount = 3; @@ -81,9 +86,110 @@ static String FormatCmdLine(const String &winmergePath, return strCommandline; } +// https://devblogs.microsoft.com/oldnewthing/20130318-00/?p=4933 +static HRESULT FindDesktopFolderView(REFIID riid, void** ppv) +{ + HRESULT hr; + CComPtr spShellWindows; + if (FAILED(hr = spShellWindows.CoCreateInstance(CLSID_ShellWindows))) + return hr; + + CComVariant vtLoc(CSIDL_DESKTOP); + CComVariant vtEmpty; + long lhwnd; + CComPtr spdisp; + if (FAILED(hr = spShellWindows->FindWindowSW( + &vtLoc, &vtEmpty, + SWC_DESKTOP, &lhwnd, SWFO_NEEDDISPATCH, &spdisp))) + return hr; + + CComPtr spBrowser; + if (FAILED(hr = CComQIPtr(spdisp)-> + QueryService(SID_STopLevelBrowser, + IID_PPV_ARGS(&spBrowser)))) + return hr; + + CComPtr spView; + if (FAILED(hr = spBrowser->QueryActiveShellView(&spView))) + return hr; + + return spView->QueryInterface(riid, ppv); +} + +// https://gitlab.com/tortoisegit/tortoisegit/-/merge_requests/187 +static HRESULT GetFolderView(IUnknown* pSite, IShellView** psv) +{ + CComPtr site(pSite); + CComPtr serviceProvider; + HRESULT hr; + if (FAILED(hr = site.QueryInterface(&serviceProvider))) + return hr; + + CComPtr shellBrowser; + if (FAILED(hr = serviceProvider->QueryService(SID_SShellBrowser, IID_PPV_ARGS(&shellBrowser)))) + return hr; + + return shellBrowser->QueryActiveShellView(psv); +} + +// https://devblogs.microsoft.com/oldnewthing/20131118-00/?p=2643 +// https://gitlab.com/tortoisegit/tortoisegit/-/merge_requests/187 +static HRESULT GetFolderAutomationObject(IUnknown* pSite, REFIID riid, void** ppv) +{ + HRESULT hr; + CComPtr spsv; + if (FAILED(hr = GetFolderView(pSite, &spsv))) + { + if (FAILED(hr = FindDesktopFolderView(IID_PPV_ARGS(&spsv)))) + return hr; + } + + CComPtr spdispView; + if (FAILED(hr = spsv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&spdispView)))) + return hr; + return spdispView->QueryInterface(riid, ppv); +} + +// https://devblogs.microsoft.com/oldnewthing/20131118-00/?p=2643 +// https://gitlab.com/tortoisegit/tortoisegit/-/merge_requests/187 +static HRESULT ShellExecuteFromExplorer( + IUnknown* pSite, + PCWSTR pszFile, + PCWSTR pszParameters = nullptr, + PCWSTR pszDirectory = nullptr, + PCWSTR pszOperation = nullptr, + int nShowCmd = SW_SHOWNORMAL) +{ + HRESULT hr; + CComPtr spFolderView; + if (FAILED(hr = GetFolderAutomationObject(pSite, IID_PPV_ARGS(&spFolderView)))) + return hr; + + CComPtr spdispShell; + if (FAILED(hr = spFolderView->get_Application(&spdispShell))) + return hr; + + // without this, the launched app is not moved to the foreground + AllowSetForegroundWindow(ASFW_ANY); + + return CComQIPtr(spdispShell) + ->ShellExecute(CComBSTR(pszFile), + CComVariant(pszParameters ? pszParameters : L""), + CComVariant(pszDirectory ? pszDirectory : L""), + CComVariant(pszOperation ? pszOperation : L""), + CComVariant(nShowCmd)); +} + static BOOL LaunchWinMerge(const String &winmergePath, - const std::vector& paths, BOOL bAlterSubFolders) + const std::vector& paths, BOOL bAlterSubFolders, IUnknown* pSite) { + if (pSite) + { + String strCommandLine = FormatCmdLine(_T(""), paths, bAlterSubFolders); + if (SUCCEEDED(ShellExecuteFromExplorer(pSite, winmergePath.c_str(), strCommandLine.c_str()))) + return TRUE; + } + String strCommandLine = FormatCmdLine(winmergePath, paths, bAlterSubFolders); // Finally start a new WinMerge process @@ -121,6 +227,7 @@ WinMergeContextMenu::WinMergeContextMenu(HINSTANCE hInstance) , m_dwMenuState(MENU_HIDDEN) , m_dwContextMenuEnabled(0) , m_langID(0) + , m_pSite(nullptr) { CRegKeyEx reg; if (reg.Open(HKEY_CURRENT_USER, f_RegDir) == ERROR_SUCCESS) @@ -317,7 +424,7 @@ HRESULT WinMergeContextMenu::InvokeCommand(DWORD verb) if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) bAlterSubFolders = TRUE; - return LaunchWinMerge(strWinMergePath, m_strPaths, bAlterSubFolders) ? S_OK : S_FALSE; + return LaunchWinMerge(strWinMergePath, m_strPaths, bAlterSubFolders, m_pSite) ? S_OK : S_FALSE; } /** diff --git a/ShellExtension/Common/WinMergeContextMenu.h b/ShellExtension/Common/WinMergeContextMenu.h index 3f267a079..8b4b4a3d6 100644 --- a/ShellExtension/Common/WinMergeContextMenu.h +++ b/ShellExtension/Common/WinMergeContextMenu.h @@ -61,6 +61,8 @@ public: std::wstring GetResourceString(UINT id) const; DWORD GetMenuState() const { return m_dwMenuState; } DWORD GetContextMenuEnabled() const { return m_dwContextMenuEnabled; } + void SetSite(IUnknown* pUnknown) { m_pSite = pUnknown; }; + const std::vector& GetPaths() const { return m_strPaths; } private: DWORD m_dwMenuState; /**< Shown menuitems */ @@ -70,5 +72,6 @@ private: inline static CLanguageSelect* s_pLang; mutable LANGID m_langID; /**< Current Language Id */ DWORD m_dwContextMenuEnabled; /**< 0, 2: context menu disabled 1: context menu enabled 3: Advanced menu enabled */ + IUnknown *m_pSite; }; diff --git a/ShellExtension/WinMergeContextMenu/dllmain.cpp b/ShellExtension/WinMergeContextMenu/dllmain.cpp index cd4a83522..33915cb5e 100644 --- a/ShellExtension/WinMergeContextMenu/dllmain.cpp +++ b/ShellExtension/WinMergeContextMenu/dllmain.cpp @@ -38,7 +38,7 @@ BOOL APIENTRY DllMain( HMODULE hModule, return TRUE; } -class WinMergeExplorerCommandBase : public RuntimeClass, IExplorerCommand> +class WinMergeExplorerCommandBase : public RuntimeClass, IExplorerCommand, IObjectWithSite> { public: WinMergeExplorerCommandBase(WinMergeContextMenu* pContextMenu) : m_pContextMenu(pContextMenu) {} @@ -101,6 +101,10 @@ public: return E_NOTIMPL; } + // IObjectWithSite + IFACEMETHODIMP SetSite(_In_ IUnknown* site) noexcept { m_site = site; m_pContextMenu->SetSite(site); return S_OK; } + IFACEMETHODIMP GetSite(_In_ REFIID riid, _COM_Outptr_ void** site) noexcept { return m_site.CopyTo(riid, site); } + protected: // code from https://github.com/microsoft/terminal/blob/main/src/cascadia/ShellExtension/OpenTerminalHere.cpp @@ -220,6 +224,7 @@ protected: return paths; } WinMergeContextMenu* m_pContextMenu; + ComPtr m_site; }; class SubExplorerCommandHandler final : public WinMergeExplorerCommandBase -- 2.11.0