Skip to content
This repository was archived by the owner on Mar 4, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Winfile.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="dbg.h" />
<ClInclude Include="explorermenu.h" />
<ClInclude Include="fmifs.h" />
<ClInclude Include="lfn.h" />
<ClInclude Include="BagOValues.h" />
Expand Down Expand Up @@ -367,6 +368,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="dbg.c" />
<ClCompile Include="explorermenu.c" />
<ClCompile Include="lfn.c" />
<ClCompile Include="lfnmisc.c" />
<ClCompile Include="numfmt.c" />
Expand Down
2 changes: 2 additions & 0 deletions src/Winfile.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<ClCompile Include="winfile.c" />
<ClCompile Include="wnetcaps.c" />
<ClCompile Include="wfloc.c" />
<ClCompile Include="explorermenu.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="dbg.h" />
Expand All @@ -62,6 +63,7 @@
<ClInclude Include="winfile.h" />
<ClInclude Include="wnetcaps.h" />
<ClInclude Include="res.h" />
<ClInclude Include="explorermenu.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="res.rc" />
Expand Down
113 changes: 113 additions & 0 deletions src/explorermenu.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#include <ShlObj.h>

//
// 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;
}
6 changes: 6 additions & 0 deletions src/explorermenu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <ShlObj.h>

int ShowExplorerContextMenu(HWND hwnd, LPCWSTR pFileName, HMENU hMenuWinFile, UINT xPos, UINT yPos);

extern IContextMenu2 *pExplorerCm2;
extern IContextMenu3 *pExplorerCm3;
14 changes: 14 additions & 0 deletions src/wfdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <commctrl.h>

#include "wfdrop.h"
#include "explorermenu.h"

WCHAR szAttr[] = L"RHSACE";

Expand Down Expand Up @@ -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_
Expand Down
12 changes: 10 additions & 2 deletions src/wfdlgs.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <dlgs.h>
#include "lfn.h"
#include "wfcopy.h"
#include "explorermenu.h"

VOID MDIClientSizeChange(HWND hwndActive, INT iFlags);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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));

Expand Down