[EXPLORER-NEW]

* Use IContextMenu for the context menus, instead of a struct with function pointers.

svn path=/branches/shell-experiments/; revision=65279
This commit is contained in:
David Quintana 2014-11-06 03:05:33 +00:00
parent fb929febc6
commit 7d0ca528ce
3 changed files with 400 additions and 369 deletions

View file

@ -155,20 +155,6 @@ _CStartMenu_Constructor(REFIID riid, void **ppv);
#define TWM_OPENSTARTMENU (WM_USER + 260)
typedef HMENU(*PCREATECTXMENU)(IN HWND hWndOwner,
IN PVOID *ppcmContext,
IN PVOID Context OPTIONAL);
typedef VOID(*PCTXMENUCOMMAND)(IN HWND hWndOwner,
IN UINT uiCmdId,
IN PVOID pcmContext OPTIONAL,
IN PVOID Context OPTIONAL);
typedef struct _TRAYWINDOW_CTXMENU
{
PCREATECTXMENU CreateCtxMenu;
PCTXMENUCOMMAND CtxMenuCommand;
} TRAYWINDOW_CTXMENU, *PTRAYWINDOW_CTXMENU;
extern const GUID IID_IShellDesktopTray;
#define INTERFACE ITrayWindow
@ -343,7 +329,7 @@ OUT HWND *phWndTaskSwitch);
* startmnu.cpp
*/
extern const TRAYWINDOW_CTXMENU StartMenuBtnCtxMenu;
HRESULT StartMenuBtnCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, IContextMenu ** ppCtxMenu);
#define INTERFACE IStartMenuSite
DECLARE_INTERFACE_(IStartMenuSite, IUnknown)

View file

@ -24,45 +24,25 @@
* Start menu button context menu
*/
// TODO: Convert into an IContextMenu
typedef struct _STARTMNU_CTMENU_CTX
class CStartMenuBtnCtxMenu :
public CComCoClass<CStartMenuBtnCtxMenu>,
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IContextMenu
{
IContextMenu *pcm;
HWND hWndOwner;
CComPtr<ITrayWindow> TrayWnd;
CComPtr<IContextMenu> pcm;
CComPtr<IShellFolder> psf;
LPITEMIDLIST pidl;
} STARTMNU_CTMENU_CTX, *PSTARTMNU_CTMENU_CTX;
static HMENU
CreateStartContextMenu(IN HWND hWndOwner,
IN PVOID *ppcmContext,
IN PVOID Context OPTIONAL);
static VOID
OnStartContextMenuCommand(IN HWND hWndOwner,
IN UINT uiCmdId,
IN PVOID pcmContext OPTIONAL,
IN PVOID Context OPTIONAL);
const TRAYWINDOW_CTXMENU StartMenuBtnCtxMenu = {
CreateStartContextMenu,
OnStartContextMenuCommand
};
static HMENU
CreateContextMenuFromShellFolderPidl(IN HWND hWndOwner,
IN OUT IShellFolder *psf,
IN OUT LPITEMIDLIST pidl,
OUT IContextMenu **ppcm)
{
HRESULT CreateContextMenuFromShellFolderPidl(HMENU hPopup)
{
CComPtr<IContextMenu> pcm;
HRESULT hRet;
HMENU hPopup;
hRet = psf->GetUIObjectOf(hWndOwner, 1, (LPCITEMIDLIST *) &pidl, IID_NULL_PPV_ARG(IContextMenu, &pcm));
if (SUCCEEDED(hRet))
{
hPopup = CreatePopupMenu();
if (hPopup != NULL)
{
hRet = pcm->QueryContextMenu(
@ -74,62 +54,18 @@ CreateContextMenuFromShellFolderPidl(IN HWND hWndOwner,
if (SUCCEEDED(hRet))
{
*ppcm = pcm;
return hPopup;
return hRet;
}
DestroyMenu(hPopup);
}
}
return NULL;
}
static VOID
OnStartContextMenuCommand(IN HWND hWndOwner,
IN UINT uiCmdId,
IN PVOID pcmContext OPTIONAL,
IN PVOID Context OPTIONAL)
{
PSTARTMNU_CTMENU_CTX psmcmc = (PSTARTMNU_CTMENU_CTX) pcmContext;
if (uiCmdId != 0)
{
if ((uiCmdId >= ID_SHELL_CMD_FIRST) && (uiCmdId <= ID_SHELL_CMD_LAST))
{
CMINVOKECOMMANDINFO cmici = { 0 };
CHAR szDir[MAX_PATH];
/* Setup and invoke the shell command */
cmici.cbSize = sizeof(cmici);
cmici.hwnd = hWndOwner;
cmici.lpVerb = (LPCSTR) MAKEINTRESOURCE(uiCmdId - ID_SHELL_CMD_FIRST);
cmici.nShow = SW_NORMAL;
/* FIXME: Support Unicode!!! */
if (SHGetPathFromIDListA(psmcmc->pidl,
szDir))
{
cmici.lpDirectory = szDir;
return E_FAIL;
}
psmcmc->pcm->InvokeCommand(&cmici);
}
else
VOID AddStartContextMenuItems(IN HMENU hPopup)
{
ITrayWindow * TrayWnd = (ITrayWindow *) Context;
TrayWnd->ExecContextMenuCmd(uiCmdId);
}
}
psmcmc->pcm->Release();
HeapFree(hProcessHeap, 0, psmcmc);
}
static VOID
AddStartContextMenuItems(IN HWND hWndOwner, IN HMENU hPopup)
{
WCHAR szBuf[MAX_PATH];
HRESULT hRet;
@ -192,72 +128,118 @@ AddStartContextMenuItems(IN HWND hWndOwner, IN HMENU hPopup)
}
}
}
}
}
static HMENU
CreateStartContextMenu(IN HWND hWndOwner,
IN PVOID *ppcmContext,
IN PVOID Context OPTIONAL)
{
LPITEMIDLIST pidlStart, pidlLast;
CComPtr<IShellFolder> psfStart;
public:
HRESULT Initialize(ITrayWindow * pTrayWnd, IN HWND hWndOwner)
{
this->TrayWnd = pTrayWnd;
this->hWndOwner = hWndOwner;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE
QueryContextMenu(HMENU hPopup,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
LPITEMIDLIST pidlStart;
CComPtr<IShellFolder> psfDesktop;
CComPtr<IContextMenu> pcm;
HRESULT hRet;
HMENU hPopup;
pidlStart = SHCloneSpecialIDList(hWndOwner,
CSIDL_STARTMENU,
TRUE);
psfDesktop = NULL;
pcm = NULL;
pidlStart = SHCloneSpecialIDList(hWndOwner, CSIDL_STARTMENU, TRUE);
if (pidlStart != NULL)
{
pidlLast = ILClone(ILFindLastID(pidlStart));
pidl = ILClone(ILFindLastID(pidlStart));
ILRemoveLastID(pidlStart);
if (pidlLast != NULL)
if (pidl != NULL)
{
hRet = SHGetDesktopFolder(&psfDesktop);
if (SUCCEEDED(hRet))
{
hRet = psfDesktop->BindToObject(pidlStart, NULL, IID_PPV_ARG(IShellFolder, &psfStart));
hRet = psfDesktop->BindToObject(pidlStart, NULL, IID_PPV_ARG(IShellFolder, &psf));
if (SUCCEEDED(hRet))
{
hPopup = CreateContextMenuFromShellFolderPidl(hWndOwner,
psfStart,
pidlLast,
&pcm);
if (hPopup != NULL)
{
PSTARTMNU_CTMENU_CTX psmcmc;
psmcmc = (PSTARTMNU_CTMENU_CTX) HeapAlloc(hProcessHeap, 0, sizeof(*psmcmc));
if (psmcmc != NULL)
{
psmcmc->pcm = pcm;
psmcmc->pidl = pidlLast;
AddStartContextMenuItems(hWndOwner,
hPopup);
*ppcmContext = psmcmc;
return hPopup;
}
else
{
DestroyMenu(hPopup);
hPopup = NULL;
CreateContextMenuFromShellFolderPidl(hPopup);
AddStartContextMenuItems(hPopup);
}
}
}
}
ILFree(pidlLast);
}
ILFree(pidlStart);
}
return NULL;
}
virtual HRESULT STDMETHODCALLTYPE
InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
{
UINT uiCmdId = (UINT)lpici->lpVerb;
if (uiCmdId != 0)
{
if ((uiCmdId >= ID_SHELL_CMD_FIRST) && (uiCmdId <= ID_SHELL_CMD_LAST))
{
CMINVOKECOMMANDINFO cmici = { 0 };
CHAR szDir[MAX_PATH];
/* Setup and invoke the shell command */
cmici.cbSize = sizeof(cmici);
cmici.hwnd = hWndOwner;
cmici.lpVerb = MAKEINTRESOURCEA(uiCmdId - ID_SHELL_CMD_FIRST);
cmici.nShow = SW_NORMAL;
/* FIXME: Support Unicode!!! */
if (SHGetPathFromIDListA(pidl, szDir))
{
cmici.lpDirectory = szDir;
}
pcm->InvokeCommand(&cmici);
}
else
{
TrayWnd->ExecContextMenuCmd(uiCmdId);
}
}
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE
GetCommandString(UINT_PTR idCmd,
UINT uType,
UINT *pwReserved,
LPSTR pszName,
UINT cchMax)
{
return E_NOTIMPL;
}
CStartMenuBtnCtxMenu()
{
}
virtual ~CStartMenuBtnCtxMenu()
{
if (pidl)
ILFree(pidl);
}
BEGIN_COM_MAP(CStartMenuBtnCtxMenu)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
END_COM_MAP()
};
HRESULT StartMenuBtnCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, IContextMenu ** ppCtxMenu)
{
CStartMenuBtnCtxMenu * mnu = new CComObject<CStartMenuBtnCtxMenu>();
mnu->Initialize(TrayWnd, hWndOwner);
*ppCtxMenu = mnu;
return S_OK;
}

View file

@ -24,7 +24,7 @@
extern HRESULT InitShellServices(HDPA * phdpa);
extern HRESULT ShutdownShellServices(HDPA hdpa);
extern const TRAYWINDOW_CTXMENU TrayWindowCtxMenu;
HRESULT TrayWindowCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, IContextMenu ** ppCtxMenu);
#define WM_APP_TRAYDESTROY (WM_APP + 0x100)
@ -70,7 +70,6 @@ class CTrayWindow :
HFONT hStartBtnFont;
HFONT hCaptionFont;
CComPtr<ITrayBandSite> TrayBandSite;
HWND hwndRebar;
HWND hwndTaskSwitch;
HWND hwndTrayNotify;
@ -84,23 +83,6 @@ class CTrayWindow :
RECT rcTrayWnd[4];
RECT rcNewPosSize;
SIZE TraySize;
union
{
DWORD Flags;
struct
{
DWORD AutoHide : 1;
DWORD AlwaysOnTop : 1;
DWORD SmSmallIcons : 1;
DWORD HideClock : 1;
DWORD Locked : 1;
/* UI Status */
DWORD InSizeMove : 1;
DWORD IsDragging : 1;
DWORD NewPosSize : 1;
};
};
NONCLIENTMETRICS ncm;
HFONT hFont;
@ -118,6 +100,26 @@ class CTrayWindow :
HDPA hdpaShellServices;
public:
CComPtr<ITrayBandSite> TrayBandSite;
union
{
DWORD Flags;
struct
{
DWORD AutoHide : 1;
DWORD AlwaysOnTop : 1;
DWORD SmSmallIcons : 1;
DWORD HideClock : 1;
DWORD Locked : 1;
/* UI Status */
DWORD InSizeMove : 1;
DWORD IsDragging : 1;
DWORD NewPosSize : 1;
};
};
public:
CTrayWindow() :
StartButton(this, 1),
@ -134,13 +136,13 @@ public:
PreviousMonitor(NULL),
DraggingPosition(0),
DraggingMonitor(NULL),
Flags(0),
hFont(NULL),
hbmStartMenu(NULL),
hwndTrayPropertiesOwner(NULL),
hwndRunFileDlgOwner(NULL),
AutoHideState(NULL),
hdpaShellServices(NULL)
hdpaShellServices(NULL),
Flags(0)
{
ZeroMemory(&StartBtnSize, sizeof(StartBtnSize));
ZeroMemory(&rcTrayWnd, sizeof(rcTrayWnd));
@ -1017,38 +1019,51 @@ ChangePos:
return cmdId;
}
UINT TrackCtxMenu(
IN const TRAYWINDOW_CTXMENU *pMenu,
HRESULT TrackCtxMenu(
IN IContextMenu * contextMenu,
IN POINT *ppt OPTIONAL,
IN HWND hwndExclude OPTIONAL,
IN BOOL TrackUp,
IN PVOID Context OPTIONAL)
{
HMENU hPopup;
UINT cmdId = 0;
PVOID pcmContext = NULL;
INT x = ppt->x;
INT y = ppt->y;
HRESULT hr;
UINT uCommand;
HMENU popup = CreatePopupMenu();
hPopup = pMenu->CreateCtxMenu(m_hWnd,
&pcmContext,
Context);
if (hPopup != NULL)
if (popup == NULL)
return E_FAIL;
TRACE("Before Query\n");
hr = contextMenu->QueryContextMenu(popup, 0, 0, UINT_MAX, CMF_NORMAL);
if (FAILED_UNEXPECTEDLY(hr))
{
cmdId = TrackMenu(
hPopup,
ppt,
hwndExclude,
TrackUp,
TRUE);
pMenu->CtxMenuCommand(m_hWnd,
cmdId,
pcmContext,
Context);
DestroyMenu(hPopup);
TRACE("Query failed\n");
DestroyMenu(popup);
return hr;
}
return cmdId;
TRACE("Before Tracking\n");
uCommand = ::TrackPopupMenuEx(popup, TPM_RETURNCMD, x, y, m_hWnd, NULL);
if (uCommand != 0)
{
TRACE("Before InvokeCommand\n");
CMINVOKECOMMANDINFO cmi = { 0 };
cmi.cbSize = sizeof(cmi);
cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
cmi.hwnd = m_hWnd;
hr = contextMenu->InvokeCommand(&cmi);
}
else
{
TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand, GetLastError());
hr = S_FALSE;
}
DestroyMenu(popup);
return hr;
}
@ -2480,12 +2495,9 @@ SetStartBtnImage:
menu is currently being shown */
if (!(StartButton.SendMessage(BM_GETSTATE, 0, 0) & BST_PUSHED))
{
TrackCtxMenu(
&StartMenuBtnCtxMenu,
ppt,
hWndExclude,
Position == ABE_BOTTOM,
this);
CComPtr<IContextMenu> ctxMenu;
StartMenuBtnCtxMenuCreator(this, m_hWnd, &ctxMenu);
TrackCtxMenu(ctxMenu, ppt, hWndExclude, Position == ABE_BOTTOM, this);
}
}
else
@ -2522,12 +2534,9 @@ SetStartBtnImage:
{
HandleTrayContextMenu:
/* Tray the default tray window context menu */
TrackCtxMenu(
&TrayWindowCtxMenu,
ppt,
NULL,
FALSE,
this);
CComPtr<IContextMenu> ctxMenu;
TrayWindowCtxMenuCreator(this, m_hWnd, &ctxMenu);
TrackCtxMenu(ctxMenu, ppt, NULL, FALSE, this);
}
}
return Ret;
@ -2816,89 +2825,6 @@ HandleTrayContextMenu:
ALT_MSG_MAP(1)
END_MSG_MAP()
/*
* Tray Window Context Menu
*/
static HMENU CreateTrayWindowContextMenu(IN HWND hWndOwner,
IN PVOID *ppcmContext,
IN PVOID Context OPTIONAL)
{
CTrayWindow *This = (CTrayWindow *) Context;
IContextMenu *pcm = NULL;
HMENU hPopup;
hPopup = LoadPopupMenu(hExplorerInstance,
MAKEINTRESOURCE(IDM_TRAYWND));
if (hPopup != NULL)
{
if (SHRestricted(REST_CLASSICSHELL) != 0)
{
DeleteMenu(hPopup,
ID_LOCKTASKBAR,
MF_BYCOMMAND);
}
CheckMenuItem(hPopup,
ID_LOCKTASKBAR,
MF_BYCOMMAND | (This->Locked ? MF_CHECKED : MF_UNCHECKED));
if (This->TrayBandSite != NULL)
{
if (SUCCEEDED(This->TrayBandSite->AddContextMenus(
hPopup,
0,
ID_SHELL_CMD_FIRST,
ID_SHELL_CMD_LAST,
CMF_NORMAL,
&pcm)))
{
TRACE("ITrayBandSite::AddContextMenus succeeded!\n");
*(IContextMenu **) ppcmContext = pcm;
}
}
}
return hPopup;
}
static VOID OnTrayWindowContextMenuCommand(IN HWND hWndOwner,
IN UINT uiCmdId,
IN PVOID pcmContext OPTIONAL,
IN PVOID Context OPTIONAL)
{
CTrayWindow *This = (CTrayWindow *) Context;
IContextMenu *pcm = (IContextMenu *) pcmContext;
if (uiCmdId != 0)
{
if (uiCmdId >= ID_SHELL_CMD_FIRST && uiCmdId <= ID_SHELL_CMD_LAST)
{
CMINVOKECOMMANDINFO cmici = { 0 };
if (pcm != NULL)
{
/* Setup and invoke the shell command */
cmici.cbSize = sizeof(cmici);
cmici.hwnd = hWndOwner;
cmici.lpVerb = (LPCSTR) MAKEINTRESOURCE(uiCmdId - ID_SHELL_CMD_FIRST);
cmici.nShow = SW_NORMAL;
pcm->InvokeCommand(
&cmici);
}
}
else
{
This->ExecContextMenuCmd(uiCmdId);
}
}
if (pcm != NULL)
pcm->Release();
}
/*****************************************************************************/
VOID TrayProcessMessages()
@ -3017,11 +2943,148 @@ HandleTrayContextMenu:
END_COM_MAP()
};
const TRAYWINDOW_CTXMENU TrayWindowCtxMenu = {
CTrayWindow::CreateTrayWindowContextMenu,
CTrayWindow::OnTrayWindowContextMenuCommand
class CTrayWindowCtxMenu :
public CComCoClass<CTrayWindowCtxMenu>,
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IContextMenu
{
HWND hWndOwner;
CComPtr<CTrayWindow> TrayWnd;
CComPtr<IContextMenu> pcm;
public:
HRESULT Initialize(ITrayWindow * pTrayWnd, IN HWND hWndOwner)
{
this->TrayWnd = (CTrayWindow *) pTrayWnd;
this->hWndOwner = hWndOwner;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE
QueryContextMenu(HMENU hPopup,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
HMENU menubase = LoadPopupMenu(hExplorerInstance, MAKEINTRESOURCE(IDM_TRAYWND));
if (menubase)
{
int count = ::GetMenuItemCount(menubase);
for (int i = 0; i < count; i++)
{
WCHAR label[128];
MENUITEMINFOW mii = { 0 };
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS
| MIIM_DATA | MIIM_STRING | MIIM_BITMAP | MIIM_FTYPE;
mii.dwTypeData = label;
mii.cch = _countof(label);
::GetMenuItemInfoW(menubase, i, TRUE, &mii);
TRACE("Adding item %d label %S type %d\n", mii.wID, mii.dwTypeData, mii.fType);
mii.fType |= MFT_RADIOCHECK;
::InsertMenuItemW(hPopup, i + 1, TRUE, &mii);
}
::DestroyMenu(menubase);
if (SHRestricted(REST_CLASSICSHELL) != 0)
{
DeleteMenu(hPopup,
ID_LOCKTASKBAR,
MF_BYCOMMAND);
}
CheckMenuItem(hPopup,
ID_LOCKTASKBAR,
MF_BYCOMMAND | (TrayWnd->Locked ? MF_CHECKED : MF_UNCHECKED));
if (TrayWnd->TrayBandSite != NULL)
{
if (SUCCEEDED(TrayWnd->TrayBandSite->AddContextMenus(
hPopup,
0,
ID_SHELL_CMD_FIRST,
ID_SHELL_CMD_LAST,
CMF_NORMAL,
&pcm)))
{
return S_OK;
}
}
}
return E_FAIL;
}
virtual HRESULT STDMETHODCALLTYPE
InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
{
UINT uiCmdId = (UINT) lpici->lpVerb;
if (uiCmdId != 0)
{
if (uiCmdId >= ID_SHELL_CMD_FIRST && uiCmdId <= ID_SHELL_CMD_LAST)
{
CMINVOKECOMMANDINFO cmici = { 0 };
if (pcm != NULL)
{
/* Setup and invoke the shell command */
cmici.cbSize = sizeof(cmici);
cmici.hwnd = hWndOwner;
cmici.lpVerb = (LPCSTR) MAKEINTRESOURCE(uiCmdId - ID_SHELL_CMD_FIRST);
cmici.nShow = SW_NORMAL;
pcm->InvokeCommand(&cmici);
}
}
else
{
TrayWnd->ExecContextMenuCmd(uiCmdId);
}
}
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE
GetCommandString(UINT_PTR idCmd,
UINT uType,
UINT *pwReserved,
LPSTR pszName,
UINT cchMax)
{
return E_NOTIMPL;
}
CTrayWindowCtxMenu()
{
}
virtual ~CTrayWindowCtxMenu()
{
}
BEGIN_COM_MAP(CTrayWindowCtxMenu)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
END_COM_MAP()
};
HRESULT TrayWindowCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, IContextMenu ** ppCtxMenu)
{
CTrayWindowCtxMenu * mnu = new CComObject<CTrayWindowCtxMenu>();
mnu->Initialize(TrayWnd, hWndOwner);
*ppCtxMenu = mnu;
return S_OK;
}
CTrayWindow * g_TrayWindow;
HRESULT