2025-11-28 00:35:46 +09:00

262 lines
6.9 KiB
C++

/**************************************************************************
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
(c) Microsoft Corporation. All Rights Reserved.
**************************************************************************/
#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#include "utils.h"
#include "resource.h"
#include <new> // std::nothrow
#define MENUVERB_DISPLAY 0
// The "terminator" ICIVERBTOIDMAP structure is {NULL, NULL, (UINT)-1,}
typedef struct
{
LPCWSTR pszCmd; // verbW
LPCSTR pszCmdA; // verbA
UINT idCmd; // hmenu id
UINT idsHelpText; // id of help text
} ICIVERBTOIDMAP;
const ICIVERBTOIDMAP c_FolderViewImplContextMenuIDMap[] =
{
{ L"display", "display", MENUVERB_DISPLAY, 0, },
{ NULL, NULL, (UINT)-1, 0, }
};
class CFolderViewImplContextMenu : public IContextMenu
, public IShellExtInit
, public IObjectWithSite
{
public:
CFolderViewImplContextMenu() : _cRef(1), _punkSite(NULL), _pdtobj(NULL)
{
DllAddRef();
}
// IUnknown
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] = {
QITABENT(CFolderViewImplContextMenu, IContextMenu),
QITABENT(CFolderViewImplContextMenu, IShellExtInit),
QITABENT(CFolderViewImplContextMenu, IObjectWithSite),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&_cRef);
}
IFACEMETHODIMP_(ULONG) Release()
{
long cRef = InterlockedDecrement(&_cRef);
if (!cRef)
{
delete this;
}
return cRef;
}
// IContextMenu
IFACEMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
IFACEMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpici);
IFACEMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pRes, LPSTR pszName, UINT cchMax);
// IShellExtInit
IFACEMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID);
// IObjectWithSite
IFACEMETHODIMP SetSite(IUnknown *punkSite);
IFACEMETHODIMP GetSite(REFIID riid, void **ppvSite);
private:
long _cRef;
IDataObject *_pdtobj;
IUnknown *_punkSite;
~CFolderViewImplContextMenu()
{
// _punkSite should be NULL due to SetSite(NULL).
if (_pdtobj)
{
_pdtobj->Release();
}
DllRelease();
}
};
HRESULT CFolderViewImplContextMenu_CreateInstance(REFIID riid, void **ppv)
{
*ppv = NULL;
CFolderViewImplContextMenu* pFolderViewImplContextMenu = new (std::nothrow) CFolderViewImplContextMenu();
HRESULT hr = pFolderViewImplContextMenu ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
hr = pFolderViewImplContextMenu->QueryInterface(riid, ppv);
pFolderViewImplContextMenu->Release();
}
return hr;
}
HRESULT CFolderViewImplContextMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT /* idCmdLast */, UINT /* uFlags */)
{
WCHAR szMenuItem[80];
LoadString(g_hInst, IDS_DISPLAY, szMenuItem, ARRAYSIZE(szMenuItem));
InsertMenu(hmenu, indexMenu++, MF_BYPOSITION, idCmdFirst + MENUVERB_DISPLAY, szMenuItem);
// other verbs could go here...
// indicate that we added one verb.
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (USHORT)(1));
}
const ICIVERBTOIDMAP* _CmdIDToMap(UINT_PTR idCmd, BOOL fUnicode, const ICIVERBTOIDMAP* pmap)
{
const ICIVERBTOIDMAP* pmapRet = NULL;
if (IS_INTRESOURCE(idCmd))
{
UINT idVerb = (UINT)idCmd;
while (!pmapRet && -1 != pmap->idCmd)
{
if (pmap->idCmd == idVerb)
{
pmapRet = pmap;
}
pmap++;
}
}
else if (fUnicode)
{
LPCWSTR pszVerb = (LPCWSTR)idCmd;
while (!pmapRet && -1 != pmap->idCmd)
{
if (pmap->pszCmd && 0 == StrCmpIC(pszVerb, pmap->pszCmd))
{
pmapRet = pmap;
}
pmap++;
}
}
else
{
LPCSTR pszVerbA = (LPCSTR)idCmd;
while (!pmapRet && -1 != pmap->idCmd)
{
if (pmap->pszCmdA && 0 == StrCmpICA(pszVerbA, pmap->pszCmdA))
{
pmapRet = pmap;
}
pmap++;
}
}
return pmapRet;
}
#define IS_UNICODE_ICI(pici) (((pici)->fMask & CMIC_MASK_UNICODE) == CMIC_MASK_UNICODE)
HRESULT _MapICIVerbToCmdID(LPCMINVOKECOMMANDINFO pici, const ICIVERBTOIDMAP* pmap, UINT* pid)
{
HRESULT hr = E_FAIL;
if (!IS_INTRESOURCE(pici->lpVerb))
{
UINT_PTR idCmd;
BOOL fUnicode;
if (IS_UNICODE_ICI(pici) && ((LPCMINVOKECOMMANDINFOEX)pici)->lpVerbW)
{
fUnicode = TRUE;
idCmd = (UINT_PTR)(((LPCMINVOKECOMMANDINFOEX)pici)->lpVerbW);
}
else
{
fUnicode = FALSE;
idCmd = (UINT_PTR)(pici->lpVerb);
}
pmap = _CmdIDToMap(idCmd, fUnicode, pmap);
if (pmap)
{
*pid = pmap->idCmd;
hr = S_OK;
}
}
else
{
*pid = LOWORD((UINT_PTR)pici->lpVerb);
hr = S_OK;
}
return hr;
}
HRESULT CFolderViewImplContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
{
HRESULT hr = E_INVALIDARG;
UINT uID;
// Is this command for us?
if (SUCCEEDED(_MapICIVerbToCmdID(pici, c_FolderViewImplContextMenuIDMap, &uID)) && uID == MENUVERB_DISPLAY && _pdtobj)
{
IShellItemArray *psia;
hr = SHCreateShellItemArrayFromDataObject(_pdtobj, IID_PPV_ARGS(&psia));
if (SUCCEEDED(hr))
{
hr = DisplayItem(psia, pici->hwnd);
psia->Release();
}
}
return hr;
}
HRESULT CFolderViewImplContextMenu::GetCommandString(UINT_PTR /* idCmd */, UINT /* uType */, UINT * /* pRes */, LPSTR /* pszName */, UINT /* cchMax */)
{
return E_NOTIMPL;
}
HRESULT CFolderViewImplContextMenu::Initialize(PCIDLIST_ABSOLUTE /* pidlFolder */, IDataObject *pdtobj, HKEY /* hkeyProgID */)
{
if (_pdtobj)
{
_pdtobj->Release();
_pdtobj = NULL;
}
_pdtobj = pdtobj;
if (pdtobj)
{
pdtobj->AddRef();
}
return S_OK;
}
HRESULT CFolderViewImplContextMenu::SetSite(IUnknown *punkSite)
{
if (_punkSite)
{
_punkSite->Release();
_punkSite = NULL;
}
_punkSite = punkSite;
if (punkSite)
{
punkSite->AddRef();
}
return S_OK;
}
HRESULT CFolderViewImplContextMenu::GetSite(REFIID riid, void **ppvSite)
{
return _punkSite ? _punkSite->QueryInterface(riid, ppvSite) : E_FAIL;
}