diff --git a/src/Winfile.vcxproj b/src/Winfile.vcxproj
index c6ac905c..89b83a84 100644
--- a/src/Winfile.vcxproj
+++ b/src/Winfile.vcxproj
@@ -297,6 +297,7 @@
+
@@ -367,6 +368,7 @@
+
diff --git a/src/Winfile.vcxproj.filters b/src/Winfile.vcxproj.filters
index aaa8f825..d3bb1061 100644
--- a/src/Winfile.vcxproj.filters
+++ b/src/Winfile.vcxproj.filters
@@ -37,6 +37,7 @@
+
@@ -62,6 +63,7 @@
+
diff --git a/src/explorermenu.c b/src/explorermenu.c
new file mode 100644
index 00000000..223bfa55
--- /dev/null
+++ b/src/explorermenu.c
@@ -0,0 +1,113 @@
+#include
+
+//
+// How to host an IContextMenu, part 1 - Initial foray
+// https://devblogs.microsoft.com/oldnewthing/20040920-00/?p=37823
+//
+// How to host an IContextMenu, part 2 - Displaying the context menu
+// https://devblogs.microsoft.com/oldnewthing/20040922-00/?p=37793
+//
+// How to host an IContextMenu, part 3 - Invocation location
+// https://devblogs.microsoft.com/oldnewthing/20040923-00/?p=37773
+//
+// How to host an IContextMenu, part 4 - Key context
+// https://devblogs.microsoft.com/oldnewthing/20040924-00/?p=37753
+//
+// How to host an IContextMenu, part 5 - Handling menu messages
+// https://devblogs.microsoft.com/oldnewthing/20040927-00/?p=37733
+//
+
+IContextMenu2 *pExplorerCm2;
+IContextMenu3 *pExplorerCm3;
+
+static HRESULT GetUIObjectOfFile(HWND hwnd, LPCWSTR pszPath, REFIID riid, void **ppv)
+{
+ *ppv = NULL;
+ HRESULT hr;
+ LPITEMIDLIST pidl;
+ SFGAOF sfgao;
+ if (SUCCEEDED(hr = SHParseDisplayName(pszPath, NULL, &pidl, 0, &sfgao)))
+ {
+ IShellFolder *psf;
+ LPCITEMIDLIST pidlChild;
+ if (SUCCEEDED(hr = SHBindToParent(pidl, &IID_IShellFolder, (void **)&psf, &pidlChild)))
+ {
+ hr = psf->lpVtbl->GetUIObjectOf(psf, hwnd, 1, &pidlChild, riid, NULL, ppv);
+ psf->lpVtbl->Release(psf);
+ }
+ CoTaskMemFree(pidl);
+ }
+ return hr;
+}
+
+// Since we are combining the WinFile menu with the explorer menu
+// all of the WinFile command IDs must be below this range
+#define EXPLORER_QCM_FIRST 0x1001
+#define EXPLORER_QCM_LAST 0x7FFF
+
+int ShowExplorerContextMenu(HWND hwnd, LPCWSTR pFileName, HMENU hMenuWinFile, UINT xPos, UINT yPos)
+{
+ POINT pt = { (long)xPos, (long)yPos };
+ if (pt.x == -1 && pt.y == -1)
+ {
+ pt.x = pt.y = 0;
+ ClientToScreen(hwnd, &pt);
+ }
+
+ int ret = 0;
+ IContextMenu *pcm;
+ if (SUCCEEDED(GetUIObjectOfFile(hwnd, pFileName, &IID_IContextMenu, (void **)&pcm)))
+ {
+ HMENU hmenu = CreatePopupMenu();
+ if (hmenu)
+ {
+ if (SUCCEEDED(pcm->lpVtbl->QueryContextMenu(pcm, hmenu, 0, EXPLORER_QCM_FIRST, EXPLORER_QCM_LAST, CMF_NORMAL)))
+ {
+ InsertMenu(hMenuWinFile, (UINT)-1, MF_BYPOSITION | MF_POPUP, (UINT_PTR)hmenu, L"Explorer");
+ pcm->lpVtbl->QueryInterface(pcm, &IID_IContextMenu2, (void **)&pExplorerCm2);
+ pcm->lpVtbl->QueryInterface(pcm, &IID_IContextMenu3, (void **)&pExplorerCm3);
+ int iCmd = TrackPopupMenuEx(hMenuWinFile, TPM_RETURNCMD, pt.x, pt.y, hwnd, NULL);
+ if (pExplorerCm2)
+ {
+ pExplorerCm2->lpVtbl->Release(pExplorerCm2);
+ pExplorerCm2 = NULL;
+ }
+ if (pExplorerCm3)
+ {
+ pExplorerCm3->lpVtbl->Release(pExplorerCm3);
+ pExplorerCm3 = NULL;
+ }
+ if (iCmd > 0 && iCmd <= EXPLORER_QCM_FIRST)
+ {
+ // The command selected was in the caller's range, they will have to execute it
+ ret = iCmd;
+ }
+ else if (iCmd > 0)
+ {
+ CMINVOKECOMMANDINFOEX info = { 0 };
+ info.cbSize = sizeof(info);
+ info.fMask = CMIC_MASK_UNICODE | CMIC_MASK_PTINVOKE;
+ if (GetKeyState(VK_CONTROL) < 0)
+ {
+ info.fMask |= CMIC_MASK_CONTROL_DOWN;
+ }
+ if (GetKeyState(VK_SHIFT) < 0)
+ {
+ info.fMask |= CMIC_MASK_SHIFT_DOWN;
+ }
+ info.hwnd = hwnd;
+ int i = iCmd - EXPLORER_QCM_FIRST;
+ info.lpVerb = MAKEINTRESOURCEA(i);
+ info.lpVerbW = MAKEINTRESOURCEW(i);
+ info.nShow = SW_SHOWNORMAL;
+ info.ptInvoke.x = xPos;
+ info.ptInvoke.y = yPos;
+ HRESULT hr = pcm->lpVtbl->InvokeCommand(pcm, (LPCMINVOKECOMMANDINFO)&info);
+ }
+ }
+ DestroyMenu(hmenu);
+ }
+ pcm->lpVtbl->Release(pcm);
+ }
+ return ret;
+}
diff --git a/src/explorermenu.h b/src/explorermenu.h
new file mode 100644
index 00000000..9bc6dddb
--- /dev/null
+++ b/src/explorermenu.h
@@ -0,0 +1,6 @@
+#include
+
+int ShowExplorerContextMenu(HWND hwnd, LPCWSTR pFileName, HMENU hMenuWinFile, UINT xPos, UINT yPos);
+
+extern IContextMenu2 *pExplorerCm2;
+extern IContextMenu3 *pExplorerCm3;
diff --git a/src/wfdir.c b/src/wfdir.c
index e1fb64c1..70ce6834 100644
--- a/src/wfdir.c
+++ b/src/wfdir.c
@@ -16,6 +16,7 @@
#include
#include "wfdrop.h"
+#include "explorermenu.h"
WCHAR szAttr[] = L"RHSACE";
@@ -429,6 +430,19 @@ DirWndProc(
static HWND hwndOwnerDraw = NULL;
+ // Process messages for the explorer context menu
+ if (pExplorerCm3) {
+ LRESULT lres;
+ if (SUCCEEDED(pExplorerCm3->lpVtbl->HandleMenuMsg2(pExplorerCm3, uMsg, wParam, lParam, &lres))) {
+ return lres;
+ }
+ }
+ else if (pExplorerCm2) {
+ if (SUCCEEDED(pExplorerCm2->lpVtbl->HandleMenuMsg(pExplorerCm2, uMsg, wParam, lParam))) {
+ return 0;
+ }
+ }
+
#ifdef PROGMANHSCROLL
//
// If the window is different and uMsg == WM_DRAWITEM _OR_
diff --git a/src/wfdlgs.c b/src/wfdlgs.c
index b315b12e..3f726077 100644
--- a/src/wfdlgs.c
+++ b/src/wfdlgs.c
@@ -14,6 +14,7 @@
#include
#include "lfn.h"
#include "wfcopy.h"
+#include "explorermenu.h"
VOID MDIClientSizeChange(HWND hwndActive, INT iFlags);
@@ -840,6 +841,7 @@ ActivateCommonContextMenu(HWND hwnd, HWND hwndLB, LPARAM lParam)
{
DWORD cmd, item;
POINT pt;
+ WCHAR *pSelectedFile = NULL;
HMENU hMenu = GetSubMenu(LoadMenu(hAppInstance, TEXT("CTXMENU")), 0);
@@ -881,14 +883,20 @@ ActivateCommonContextMenu(HWND hwnd, HWND hwndLB, LPARAM lParam)
SendMessage(hwndLB, LB_SETSEL, (WPARAM)TRUE, (LPARAM)item);
BOOL bDir = FALSE;
- SendMessage(hwnd, FS_GETSELECTION, 5, (LPARAM)&bDir);
+ pSelectedFile = (WCHAR *)SendMessage(hwnd, FS_GETSELECTION, 5, (LPARAM)&bDir);
if (bDir)
EnableMenuItem(hMenu, IDM_EDIT, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
}
}
}
- cmd = TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0, hwnd, NULL);
+ if (pSelectedFile != NULL) {
+ cmd = ShowExplorerContextMenu(hwnd, pSelectedFile, hMenu, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+ }
+ else
+ {
+ cmd = TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0, hwnd, NULL);
+ }
if (cmd != 0)
PostMessage(hwndFrame, WM_COMMAND, GET_WM_COMMAND_MPS(cmd, 0, 0));