From a7a406e5538b343d87b3221b13b7bf3503bbfd70 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Wed, 22 Jan 2020 01:03:00 -0500 Subject: preparing for multiple origins shell menus split exec() from createMenu() --- src/envshell.cpp | 128 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 85 insertions(+), 43 deletions(-) (limited to 'src/envshell.cpp') diff --git a/src/envshell.cpp b/src/envshell.cpp index 7754928e..992ce1ef 100644 --- a/src/envshell.cpp +++ b/src/envshell.cpp @@ -65,15 +65,7 @@ public: WndProcFilter(QMainWindow* mw, IContextMenu* cm) : m_mw(mw), m_cm(cm), m_cm2(nullptr), m_cm3(nullptr) { - IContextMenu2* cm2 = nullptr; - if (SUCCEEDED(cm->QueryInterface(IID_IContextMenu2, (void**)&cm2))) { - m_cm2.reset(cm2); - } - - IContextMenu3* cm3 = nullptr; - if (SUCCEEDED(cm->QueryInterface(IID_IContextMenu3, (void**)&cm3))) { - m_cm3.reset(cm3); - } + createInterfaces(); } ~WndProcFilter() @@ -86,6 +78,9 @@ public: bool nativeEventFilter(const QByteArray& type, void* m, long* lresultOut) override { MSG* msg = (MSG*)m; + if (!msg) { + return false; + } if (msg->message == WM_MENUSELECT) { HANDLE_WM_MENUSELECT(msg->hwnd, msg->wParam, msg->lParam, onMenuSelect); @@ -129,6 +124,23 @@ private: COMPtr m_cm2; COMPtr m_cm3; + void createInterfaces() + { + if (!m_cm) { + return; + } + + IContextMenu2* cm2 = nullptr; + if (SUCCEEDED(m_cm->QueryInterface(IID_IContextMenu2, (void**)&cm2))) { + m_cm2.reset(cm2); + } + + IContextMenu3* cm3 = nullptr; + if (SUCCEEDED(m_cm->QueryInterface(IID_IContextMenu3, (void**)&cm3))) { + m_cm3.reset(cm3); + } + } + // adapted from // https://devblogs.microsoft.com/oldnewthing/20040928-00/?p=37723 // @@ -232,14 +244,52 @@ void ShellMenu::addFile(QFileInfo fi) } void ShellMenu::exec(QWidget* parent, const QPoint& pos) +{ + auto* mw = getMainWindow(parent); + HMENU menu = getMenu(); + if (!menu) { + return; + } + + try + { + const int cmd = runMenu(mw, m_cm.get(), m_menu.get(), pos); + if (cmd <= 0) { + return; + } + + invoke(mw, pos, cmd - QCM_FIRST, m_cm.get()); + } + catch(MenuFailed& e) + { + if (m_files.size() == 1) { + log::error( + "can't exec shell menu for '{}': {}", + QDir::toNativeSeparators(m_files[0].absoluteFilePath()), e.what()); + } else { + log::error( + "can't exec shell menu for {} files: {}", + m_files.size(), e.what()); + } + } +} + +HMENU ShellMenu::getMenu() +{ + if (!m_menu) { + createMenu(); + } + + return m_menu.get(); +} + +void ShellMenu::createMenu() { if (m_files.empty()) { log::warn("showShellMenu(): no files given"); return; } - auto* mw = getMainWindow(parent); - try { auto idls = createIdls(m_files); @@ -252,27 +302,12 @@ void ShellMenu::exec(QWidget* parent, const QPoint& pos) IdlsFreer freer(idls); auto array = createItemArray(idls); - auto cm = createContextMenu(array.get()); - auto hmenu = createMenu(cm.get()); - - const int cmd = runMenu(mw, cm.get(), hmenu.get(), pos); - if (cmd <= 0) { - return; - } - - invoke(mw, pos, cmd - QCM_FIRST, cm.get()); + m_cm = createContextMenu(array.get()); + m_menu = createMenu(m_cm.get()); } catch(DummyMenu& dm) { - try - { - showDummyMenu(mw, pos, dm.what()); - } - catch(MenuFailed& e) - { - log::error("{}", dm.what()); - log::error("additionally, creating the dummy menu failed: {}", e.what()); - } + m_menu = createDummyMenu(dm.what()); } catch(MenuFailed& e) { @@ -285,27 +320,34 @@ void ShellMenu::exec(QWidget* parent, const QPoint& pos) "can't create shell menu for {} files: {}", m_files.size(), e.what()); } + + m_menu = createDummyMenu(QObject::tr("No menu available")); } } -void ShellMenu::showDummyMenu( - QMainWindow* mw, const QPoint& pos, const QString& what) +HMenuPtr ShellMenu::createDummyMenu(const QString& what) { - HMENU menu = CreatePopupMenu(); - if (!menu) { - const auto e = GetLastError(); - throw MenuFailed(e, "CreatePopupMenu failed"); - } + try + { + HMENU menu = CreatePopupMenu(); + if (!menu) { + const auto e = GetLastError(); + throw MenuFailed(e, "CreatePopupMenu failed"); + } - if (!AppendMenuW(menu, MF_STRING | MF_DISABLED, 0, what.toStdWString().c_str())) { - const auto e = GetLastError(); - throw MenuFailed(e, "AppendMenuW failed"); + if (!AppendMenuW(menu, MF_STRING | MF_DISABLED, 0, what.toStdWString().c_str())) { + const auto e = GetLastError(); + throw MenuFailed(e, "AppendMenuW failed"); + } + + return HMenuPtr(menu); } + catch(MenuFailed& e) + { + log::error("{}", what); + log::error("additionally, creating the dummy menu failed: {}", e.what()); - const auto hwnd = (HWND)mw->winId(); - if (!TrackPopupMenuEx(menu, 0, pos.x(), pos.y(), hwnd, nullptr)) { - const auto e = GetLastError(); - throw MenuFailed(e, "TrackPopupMenuEx failed"); + return {}; } } -- cgit v1.3.1