mirror of
https://github.com/reactos/reactos.git
synced 2024-10-31 11:56:26 +00:00
f66525ee02
svn path=/branches/ntvdm/; revision=59665
1786 lines
51 KiB
C++
1786 lines
51 KiB
C++
/*
|
|
* PROJECT: shell32
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: dll/win32/shell32/shv_item_new.c
|
|
* PURPOSE: provides default context menu implementation
|
|
* PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
|
|
*/
|
|
|
|
/*
|
|
TODO:
|
|
The code in NotifyShellViewWindow to deliver commands to the view is broken. It is an excellent
|
|
example of the wrong way to do it.
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(dmenu);
|
|
|
|
typedef struct _DynamicShellEntry_
|
|
{
|
|
UINT iIdCmdFirst;
|
|
UINT NumIds;
|
|
CLSID ClassID;
|
|
IContextMenu *pCM;
|
|
struct _DynamicShellEntry_ *pNext;
|
|
} DynamicShellEntry, *PDynamicShellEntry;
|
|
|
|
typedef struct _StaticShellEntry_
|
|
{
|
|
LPWSTR szVerb;
|
|
LPWSTR szClass;
|
|
struct _StaticShellEntry_ *pNext;
|
|
} StaticShellEntry, *PStaticShellEntry;
|
|
|
|
class CDefaultContextMenu :
|
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
|
public IContextMenu2
|
|
{
|
|
private:
|
|
DEFCONTEXTMENU m_Dcm;
|
|
IDataObject *m_pDataObj;
|
|
LPCITEMIDLIST m_pidlFolder;
|
|
DWORD m_bGroupPolicyActive;
|
|
PDynamicShellEntry m_pDynamicEntries; /* first dynamic shell extension entry */
|
|
UINT m_iIdSHEFirst; /* first used id */
|
|
UINT m_iIdSHELast; /* last used id */
|
|
PStaticShellEntry m_pStaticEntries; /* first static shell extension entry */
|
|
UINT m_iIdSCMFirst; /* first static used id */
|
|
UINT m_iIdSCMLast; /* last static used id */
|
|
|
|
void AddStaticEntry(LPCWSTR pwszVerb, LPCWSTR pwszClass);
|
|
void AddStaticEntryForKey(HKEY hKey, LPCWSTR pwszClass);
|
|
void AddStaticEntryForFileClass(LPCWSTR pwszExt);
|
|
BOOL IsShellExtensionAlreadyLoaded(const CLSID *pclsid);
|
|
HRESULT LoadDynamicContextMenuHandler(HKEY hKey, const CLSID *pclsid);
|
|
BOOL EnumerateDynamicContextHandlerForKey(HKEY hRootKey);
|
|
UINT InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu, UINT IndexMenu, UINT idCmdFirst, UINT idCmdLast);
|
|
UINT BuildBackgroundContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
|
|
UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT IndexMenu);
|
|
UINT BuildShellItemContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
|
|
HRESULT DoPaste(LPCMINVOKECOMMANDINFO lpcmi);
|
|
HRESULT DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi);
|
|
HRESULT DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi);
|
|
HRESULT DoDelete(LPCMINVOKECOMMANDINFO lpcmi);
|
|
HRESULT DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi, BOOL bCopy);
|
|
HRESULT DoRename(LPCMINVOKECOMMANDINFO lpcmi);
|
|
HRESULT DoProperties(LPCMINVOKECOMMANDINFO lpcmi);
|
|
HRESULT DoFormat(LPCMINVOKECOMMANDINFO lpcmi);
|
|
HRESULT DoDynamicShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
|
|
HRESULT DoStaticShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
|
|
DWORD BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi, PStaticShellEntry pEntry);
|
|
HRESULT TryToBrowse(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, DWORD wFlags);
|
|
HRESULT InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, PStaticShellEntry pEntry);
|
|
|
|
public:
|
|
CDefaultContextMenu();
|
|
~CDefaultContextMenu();
|
|
HRESULT WINAPI Initialize(const DEFCONTEXTMENU *pdcm);
|
|
|
|
// IContextMenu
|
|
virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
|
|
virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi);
|
|
virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen);
|
|
|
|
// IContextMenu2
|
|
virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
BEGIN_COM_MAP(CDefaultContextMenu)
|
|
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
|
|
COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
|
|
END_COM_MAP()
|
|
};
|
|
|
|
CDefaultContextMenu::CDefaultContextMenu()
|
|
{
|
|
memset(&m_Dcm, 0, sizeof(m_Dcm));
|
|
m_pDataObj = NULL;
|
|
m_pidlFolder = NULL;
|
|
m_bGroupPolicyActive = 0;
|
|
m_pDynamicEntries = NULL;
|
|
m_iIdSHEFirst = 0;
|
|
m_iIdSHELast = 0;
|
|
m_pStaticEntries = NULL;
|
|
m_iIdSCMFirst = 0;
|
|
m_iIdSCMLast = 0;
|
|
}
|
|
|
|
CDefaultContextMenu::~CDefaultContextMenu()
|
|
{
|
|
/* Free dynamic shell extension entries */
|
|
PDynamicShellEntry pDynamicEntry = m_pDynamicEntries, pNextDynamic;
|
|
while (pDynamicEntry)
|
|
{
|
|
pNextDynamic = pDynamicEntry->pNext;
|
|
pDynamicEntry->pCM->Release();
|
|
HeapFree(GetProcessHeap(), 0, pDynamicEntry);
|
|
pDynamicEntry = pNextDynamic;
|
|
}
|
|
|
|
/* Free static shell extension entries */
|
|
PStaticShellEntry pStaticEntry = m_pStaticEntries, pNextStatic;
|
|
while (pStaticEntry)
|
|
{
|
|
pNextStatic = pStaticEntry->pNext;
|
|
HeapFree(GetProcessHeap(), 0, pStaticEntry->szClass);
|
|
HeapFree(GetProcessHeap(), 0, pStaticEntry->szVerb);
|
|
HeapFree(GetProcessHeap(), 0, pStaticEntry);
|
|
pStaticEntry = pNextStatic;
|
|
}
|
|
|
|
if (m_pidlFolder)
|
|
ILFree((_ITEMIDLIST*)m_pidlFolder);
|
|
if (m_pDataObj)
|
|
m_pDataObj->Release();
|
|
}
|
|
|
|
HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm)
|
|
{
|
|
IDataObject *pDataObj;
|
|
|
|
TRACE("cidl %u\n", pdcm->cidl);
|
|
if (SUCCEEDED(SHCreateDataObject(pdcm->pidlFolder, pdcm->cidl, pdcm->apidl, NULL, IID_IDataObject, (void**)&pDataObj)))
|
|
m_pDataObj = pDataObj;
|
|
|
|
if (!pdcm->cidl)
|
|
{
|
|
/* Init pidlFolder only if it is background context menu. See IShellExtInit::Initialize */
|
|
if (pdcm->pidlFolder)
|
|
m_pidlFolder = ILClone(pdcm->pidlFolder);
|
|
else
|
|
{
|
|
IPersistFolder2 *pf = NULL;
|
|
if (SUCCEEDED(pdcm->psf->QueryInterface(IID_IPersistFolder2, (PVOID*)&pf)))
|
|
{
|
|
if (FAILED(pf->GetCurFolder((_ITEMIDLIST**)&m_pidlFolder)))
|
|
ERR("GetCurFolder failed\n");
|
|
pf->Release();
|
|
}
|
|
}
|
|
TRACE("pidlFolder %p\n", m_pidlFolder);
|
|
}
|
|
|
|
CopyMemory(&m_Dcm, pdcm, sizeof(DEFCONTEXTMENU));
|
|
return S_OK;
|
|
}
|
|
|
|
void
|
|
CDefaultContextMenu::AddStaticEntry(const WCHAR *szVerb, const WCHAR *szClass)
|
|
{
|
|
PStaticShellEntry pEntry = m_pStaticEntries, pLastEntry = NULL;
|
|
while(pEntry)
|
|
{
|
|
if (!wcsicmp(pEntry->szVerb, szVerb))
|
|
{
|
|
/* entry already exists */
|
|
return;
|
|
}
|
|
pLastEntry = pEntry;
|
|
pEntry = pEntry->pNext;
|
|
}
|
|
|
|
TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb), debugstr_w(szClass));
|
|
|
|
pEntry = (StaticShellEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry));
|
|
if (pEntry)
|
|
{
|
|
pEntry->pNext = NULL;
|
|
pEntry->szVerb = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb) + 1) * sizeof(WCHAR));
|
|
if (pEntry->szVerb)
|
|
wcscpy(pEntry->szVerb, szVerb);
|
|
pEntry->szClass = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szClass) + 1) * sizeof(WCHAR));
|
|
if (pEntry->szClass)
|
|
wcscpy(pEntry->szClass, szClass);
|
|
}
|
|
|
|
if (!wcsicmp(szVerb, L"open"))
|
|
{
|
|
/* open verb is always inserted in front */
|
|
pEntry->pNext = m_pStaticEntries;
|
|
m_pStaticEntries = pEntry;
|
|
}
|
|
else if (pLastEntry)
|
|
pLastEntry->pNext = pEntry;
|
|
else
|
|
m_pStaticEntries = pEntry;
|
|
}
|
|
|
|
void
|
|
CDefaultContextMenu::AddStaticEntryForKey(HKEY hKey, const WCHAR *pwszClass)
|
|
{
|
|
WCHAR wszName[40];
|
|
DWORD cchName, dwIndex = 0;
|
|
|
|
TRACE("AddStaticEntryForKey %x %ls\n", hKey, pwszClass);
|
|
|
|
while(TRUE)
|
|
{
|
|
cchName = _countof(wszName);
|
|
if (RegEnumKeyExW(hKey, dwIndex++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
|
|
break;
|
|
|
|
AddStaticEntry(wszName, pwszClass);
|
|
}
|
|
}
|
|
|
|
void
|
|
CDefaultContextMenu::AddStaticEntryForFileClass(const WCHAR * szExt)
|
|
{
|
|
WCHAR szBuffer[100];
|
|
HKEY hKey;
|
|
LONG result;
|
|
DWORD dwBuffer;
|
|
UINT Length;
|
|
static WCHAR szShell[] = L"\\shell";
|
|
static WCHAR szShellAssoc[] = L"SystemFileAssociations\\";
|
|
|
|
TRACE("AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt));
|
|
|
|
Length = wcslen(szExt);
|
|
if (Length + (sizeof(szShell) / sizeof(WCHAR)) + 1 < sizeof(szBuffer) / sizeof(WCHAR))
|
|
{
|
|
wcscpy(szBuffer, szExt);
|
|
wcscpy(&szBuffer[Length], szShell);
|
|
result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
|
|
if (result == ERROR_SUCCESS)
|
|
{
|
|
szBuffer[Length] = 0;
|
|
AddStaticEntryForKey(hKey, szExt);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
dwBuffer = sizeof(szBuffer);
|
|
result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, NULL, RRF_RT_REG_SZ, NULL, (LPBYTE)szBuffer, &dwBuffer);
|
|
if (result == ERROR_SUCCESS)
|
|
{
|
|
Length = wcslen(szBuffer);
|
|
if (Length + (sizeof(szShell) / sizeof(WCHAR)) + 1 < sizeof(szBuffer) / sizeof(WCHAR))
|
|
{
|
|
wcscpy(&szBuffer[Length], szShell);
|
|
TRACE("szBuffer %s\n", debugstr_w(szBuffer));
|
|
|
|
result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
|
|
if (result == ERROR_SUCCESS)
|
|
{
|
|
szBuffer[Length] = 0;
|
|
AddStaticEntryForKey(hKey, szBuffer);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
wcscpy(szBuffer, szShellAssoc);
|
|
dwBuffer = sizeof(szBuffer) - sizeof(szShellAssoc) - sizeof(WCHAR);
|
|
result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, L"PerceivedType", RRF_RT_REG_SZ, NULL, (LPBYTE)&szBuffer[_countof(szShellAssoc) - 1], &dwBuffer);
|
|
if (result == ERROR_SUCCESS)
|
|
{
|
|
Length = wcslen(&szBuffer[_countof(szShellAssoc)]) + _countof(szShellAssoc);
|
|
wcscat(szBuffer, L"\\shell");
|
|
TRACE("szBuffer %s\n", debugstr_w(szBuffer));
|
|
|
|
result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
|
|
if (result == ERROR_SUCCESS)
|
|
{
|
|
szBuffer[Length] = 0;
|
|
AddStaticEntryForKey(hKey, szBuffer);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
BOOL
|
|
HasClipboardData()
|
|
{
|
|
BOOL bRet = FALSE;
|
|
IDataObject *pDataObj;
|
|
|
|
if(SUCCEEDED(OleGetClipboard(&pDataObj)))
|
|
{
|
|
STGMEDIUM medium;
|
|
FORMATETC formatetc;
|
|
|
|
TRACE("pDataObj=%p\n", pDataObj);
|
|
|
|
/* Set the FORMATETC structure*/
|
|
InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
|
|
if(SUCCEEDED(pDataObj->GetData(&formatetc, &medium)))
|
|
{
|
|
bRet = TRUE;
|
|
ReleaseStgMedium(&medium);
|
|
}
|
|
|
|
pDataObj->Release();
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
DisablePasteOptions(HMENU hMenu)
|
|
{
|
|
MENUITEMINFOW mii;
|
|
|
|
mii.cbSize = sizeof(mii);
|
|
mii.fMask = MIIM_STATE;
|
|
mii.fState = MFS_DISABLED;
|
|
|
|
TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERT, FALSE, &mii));
|
|
TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERTLINK, FALSE, &mii));
|
|
}
|
|
|
|
BOOL
|
|
CDefaultContextMenu::IsShellExtensionAlreadyLoaded(const CLSID *pclsid)
|
|
{
|
|
PDynamicShellEntry pEntry = m_pDynamicEntries;
|
|
|
|
while (pEntry)
|
|
{
|
|
if (!memcmp(&pEntry->ClassID, pclsid, sizeof(CLSID)))
|
|
return TRUE;
|
|
pEntry = pEntry->pNext;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT
|
|
CDefaultContextMenu::LoadDynamicContextMenuHandler(HKEY hKey, const CLSID *pclsid)
|
|
{
|
|
HRESULT hr;
|
|
|
|
TRACE("LoadDynamicContextMenuHandler entered with This %p hKey %p pclsid %s\n", this, hKey, wine_dbgstr_guid(pclsid));
|
|
|
|
if (IsShellExtensionAlreadyLoaded(pclsid))
|
|
return S_OK;
|
|
|
|
IContextMenu *pcm;
|
|
hr = SHCoCreateInstance(NULL, pclsid, NULL, IID_IContextMenu, (void**)&pcm);
|
|
if (hr != S_OK)
|
|
{
|
|
ERR("SHCoCreateInstance failed %x\n", GetLastError());
|
|
return hr;
|
|
}
|
|
|
|
IShellExtInit *pExtInit;
|
|
hr = pcm->QueryInterface(IID_IShellExtInit, (void**)&pExtInit);
|
|
if (hr != S_OK)
|
|
{
|
|
ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
|
|
pcm->Release();
|
|
return hr;
|
|
}
|
|
|
|
hr = pExtInit->Initialize(m_pidlFolder, m_pDataObj, hKey);
|
|
pExtInit->Release();
|
|
if (hr != S_OK)
|
|
{
|
|
TRACE("Failed to initialize shell extension error %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
|
|
pcm->Release();
|
|
return hr;
|
|
}
|
|
|
|
PDynamicShellEntry pEntry = (DynamicShellEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry));
|
|
if (!pEntry)
|
|
{
|
|
pcm->Release();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
pEntry->iIdCmdFirst = 0;
|
|
pEntry->pNext = NULL;
|
|
pEntry->NumIds = 0;
|
|
pEntry->pCM = pcm;
|
|
memcpy(&pEntry->ClassID, pclsid, sizeof(CLSID));
|
|
|
|
if (m_pDynamicEntries)
|
|
{
|
|
PDynamicShellEntry pLastEntry = m_pDynamicEntries;
|
|
|
|
while (pLastEntry->pNext)
|
|
pLastEntry = pLastEntry->pNext;
|
|
|
|
pLastEntry->pNext = pEntry;
|
|
}
|
|
else
|
|
m_pDynamicEntries = pEntry;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
BOOL
|
|
CDefaultContextMenu::EnumerateDynamicContextHandlerForKey(HKEY hRootKey)
|
|
{
|
|
|
|
WCHAR wszName[MAX_PATH], wszBuf[MAX_PATH], *pwszClsid;
|
|
DWORD cchName;
|
|
HRESULT hr;
|
|
HKEY hKey;
|
|
|
|
if (RegOpenKeyExW(hRootKey, L"shellex\\ContextMenuHandlers", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
|
|
{
|
|
TRACE("RegOpenKeyExW failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD dwIndex = 0;
|
|
while (TRUE)
|
|
{
|
|
cchName = _countof(wszName);
|
|
if (RegEnumKeyExW(hKey, dwIndex++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
|
|
break;
|
|
|
|
/* Key name or key value is CLSID */
|
|
CLSID clsid;
|
|
hr = CLSIDFromString(wszName, &clsid);
|
|
if (hr == S_OK)
|
|
pwszClsid = wszName;
|
|
else
|
|
{
|
|
DWORD cchBuf = _countof(wszBuf);
|
|
if (RegGetValueW(hKey, wszName, NULL, RRF_RT_REG_SZ, NULL, wszBuf, &cchBuf) == ERROR_SUCCESS)
|
|
hr = CLSIDFromString(wszBuf, &clsid);
|
|
pwszClsid = wszBuf;
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (m_bGroupPolicyActive)
|
|
{
|
|
if (RegGetValueW(HKEY_LOCAL_MACHINE,
|
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
|
|
pwszClsid,
|
|
RRF_RT_REG_SZ,
|
|
NULL,
|
|
NULL,
|
|
NULL) == ERROR_SUCCESS)
|
|
{
|
|
LoadDynamicContextMenuHandler(hKey, &clsid);
|
|
}
|
|
}
|
|
else
|
|
LoadDynamicContextMenuHandler(hKey, &clsid);
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
return TRUE;
|
|
}
|
|
|
|
UINT
|
|
CDefaultContextMenu::InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu, UINT IndexMenu, UINT idCmdFirst, UINT idCmdLast)
|
|
{
|
|
if (!m_pDynamicEntries)
|
|
{
|
|
m_iIdSHEFirst = 0;
|
|
m_iIdSHELast = 0;
|
|
return IndexMenu;
|
|
}
|
|
|
|
PDynamicShellEntry pEntry = m_pDynamicEntries;
|
|
idCmdFirst = 0x5000;
|
|
idCmdLast = 0x6000;
|
|
m_iIdSHEFirst = idCmdFirst;
|
|
do
|
|
{
|
|
HRESULT hr = pEntry->pCM->QueryContextMenu(hMenu, IndexMenu++, idCmdFirst, idCmdLast, CMF_NORMAL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pEntry->iIdCmdFirst = idCmdFirst;
|
|
pEntry->NumIds = LOWORD(hr);
|
|
IndexMenu += pEntry->NumIds;
|
|
idCmdFirst += pEntry->NumIds + 0x10;
|
|
}
|
|
TRACE("pEntry %p hr %x contextmenu %p cmdfirst %x num ids %x\n", pEntry, hr, pEntry->pCM, pEntry->iIdCmdFirst, pEntry->NumIds);
|
|
pEntry = pEntry->pNext;
|
|
} while (pEntry);
|
|
|
|
m_iIdSHELast = idCmdFirst;
|
|
TRACE("SH_LoadContextMenuHandlers first %x last %x\n", m_iIdSHEFirst, m_iIdSHELast);
|
|
return IndexMenu;
|
|
}
|
|
|
|
UINT
|
|
CDefaultContextMenu::BuildBackgroundContextMenu(
|
|
HMENU hMenu,
|
|
UINT iIdCmdFirst,
|
|
UINT iIdCmdLast,
|
|
UINT uFlags)
|
|
{
|
|
UINT IndexMenu = 0;
|
|
HMENU hSubMenu;
|
|
|
|
TRACE("BuildBackgroundContextMenu entered\n");
|
|
|
|
if (!_ILIsDesktop(m_pidlFolder))
|
|
{
|
|
WCHAR wszBuf[MAX_PATH];
|
|
|
|
/* view option is only available in browsing mode */
|
|
hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_001");
|
|
if (hSubMenu && LoadStringW(shell32_hInstance, FCIDM_SHVIEW_VIEW, wszBuf, _countof(wszBuf)))
|
|
{
|
|
TRACE("wszBuf %s\n", debugstr_w(wszBuf));
|
|
|
|
MENUITEMINFOW mii;
|
|
ZeroMemory(&mii, sizeof(mii));
|
|
mii.cbSize = sizeof(mii);
|
|
mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU | MIIM_ID;
|
|
mii.fType = MFT_STRING;
|
|
mii.wID = iIdCmdFirst++;
|
|
mii.dwTypeData = wszBuf;
|
|
mii.cch = wcslen(mii.dwTypeData);
|
|
mii.fState = MFS_ENABLED;
|
|
mii.hSubMenu = hSubMenu;
|
|
InsertMenuItemW(hMenu, IndexMenu++, TRUE, &mii);
|
|
DestroyMenu(hSubMenu);
|
|
}
|
|
}
|
|
|
|
hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_002");
|
|
if (hSubMenu)
|
|
{
|
|
/* merge general background context menu in */
|
|
iIdCmdFirst = Shell_MergeMenus(hMenu, GetSubMenu(hSubMenu, 0), IndexMenu, 0, 0xFFFF, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS) + 1;
|
|
DestroyMenu(hSubMenu);
|
|
}
|
|
|
|
if (!HasClipboardData())
|
|
{
|
|
TRACE("disabling paste options\n");
|
|
DisablePasteOptions(hMenu);
|
|
}
|
|
|
|
/* Directory is progid of filesystem folders only */
|
|
LPITEMIDLIST pidlFolderLast = ILFindLastID(m_pidlFolder);
|
|
if (_ILIsDesktop(pidlFolderLast) || _ILIsDrive(pidlFolderLast) || _ILIsFolder(pidlFolderLast))
|
|
{
|
|
/* Load context menu handlers */
|
|
TRACE("Add background handlers: %p\n", m_pidlFolder);
|
|
HKEY hKey;
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory\\Background", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
EnumerateDynamicContextHandlerForKey(hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
if (InsertMenuItemsOfDynamicContextMenuExtension(hMenu, GetMenuItemCount(hMenu) - 1, iIdCmdFirst, iIdCmdLast))
|
|
{
|
|
/* seperate dynamic context menu items */
|
|
_InsertMenuItemW(hMenu, GetMenuItemCount(hMenu) - 1, TRUE, -1, MFT_SEPARATOR, NULL, MFS_ENABLED);
|
|
}
|
|
}
|
|
|
|
return iIdCmdLast;
|
|
}
|
|
|
|
UINT
|
|
CDefaultContextMenu::AddStaticContextMenusToMenu(
|
|
HMENU hMenu,
|
|
UINT IndexMenu)
|
|
{
|
|
MENUITEMINFOW mii;
|
|
UINT idResource;
|
|
WCHAR wszVerb[40];
|
|
UINT fState;
|
|
|
|
mii.cbSize = sizeof(mii);
|
|
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
|
|
mii.fType = MFT_STRING;
|
|
mii.wID = 0x4000;
|
|
mii.dwTypeData = NULL;
|
|
m_iIdSCMFirst = mii.wID;
|
|
|
|
PStaticShellEntry pEntry = m_pStaticEntries;
|
|
|
|
while (pEntry)
|
|
{
|
|
fState = MFS_ENABLED;
|
|
mii.dwTypeData = NULL;
|
|
|
|
if (!wcsicmp(pEntry->szVerb, L"open"))
|
|
{
|
|
fState |= MFS_DEFAULT;
|
|
idResource = IDS_OPEN_VERB;
|
|
}
|
|
else if (!wcsicmp(pEntry->szVerb, L"explore"))
|
|
idResource = IDS_EXPLORE_VERB;
|
|
else if (!wcsicmp(pEntry->szVerb, L"runas"))
|
|
idResource = IDS_RUNAS_VERB;
|
|
else if (!wcsicmp(pEntry->szVerb, L"edit"))
|
|
idResource = IDS_EDIT_VERB;
|
|
else if (!wcsicmp(pEntry->szVerb, L"find"))
|
|
idResource = IDS_FIND_VERB;
|
|
else if (!wcsicmp(pEntry->szVerb, L"print"))
|
|
idResource = IDS_PRINT_VERB;
|
|
else if (!wcsicmp(pEntry->szVerb, L"printto"))
|
|
{
|
|
pEntry = pEntry->pNext;
|
|
continue;
|
|
}
|
|
else
|
|
idResource = 0;
|
|
|
|
/* By default use verb for menu item name */
|
|
mii.dwTypeData = pEntry->szVerb;
|
|
|
|
if (idResource > 0)
|
|
{
|
|
if (LoadStringW(shell32_hInstance, idResource, wszVerb, _countof(wszVerb)))
|
|
mii.dwTypeData = wszVerb; /* use translated verb */
|
|
else
|
|
ERR("Failed to load string\n");
|
|
}
|
|
else
|
|
{
|
|
WCHAR wszKey[256];
|
|
HRESULT hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"%s\\shell\\%s", pEntry->szClass, pEntry->szVerb);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DWORD cbVerb = sizeof(wszVerb);
|
|
|
|
if (RegGetValueW(HKEY_CLASSES_ROOT, wszKey, NULL, RRF_RT_REG_SZ, NULL, wszVerb, &cbVerb) == ERROR_SUCCESS)
|
|
mii.dwTypeData = wszVerb; /* use description for the menu entry */
|
|
}
|
|
}
|
|
|
|
mii.cch = wcslen(mii.dwTypeData);
|
|
mii.fState = fState;
|
|
InsertMenuItemW(hMenu, IndexMenu++, TRUE, &mii);
|
|
|
|
mii.wID++;
|
|
pEntry = pEntry->pNext;
|
|
}
|
|
|
|
m_iIdSCMLast = mii.wID - 1;
|
|
return IndexMenu;
|
|
}
|
|
|
|
void WINAPI _InsertMenuItemW(
|
|
HMENU hMenu,
|
|
UINT indexMenu,
|
|
BOOL fByPosition,
|
|
UINT wID,
|
|
UINT fType,
|
|
LPCWSTR dwTypeData,
|
|
UINT fState)
|
|
{
|
|
MENUITEMINFOW mii;
|
|
WCHAR wszText[100];
|
|
|
|
ZeroMemory(&mii, sizeof(mii));
|
|
mii.cbSize = sizeof(mii);
|
|
if (fType == MFT_SEPARATOR)
|
|
mii.fMask = MIIM_ID | MIIM_TYPE;
|
|
else if (fType == MFT_STRING)
|
|
{
|
|
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
|
|
if ((ULONG_PTR)HIWORD((ULONG_PTR)dwTypeData) == 0)
|
|
{
|
|
if (LoadStringW(shell32_hInstance, LOWORD((ULONG_PTR)dwTypeData), wszText, _countof(wszText)))
|
|
mii.dwTypeData = wszText;
|
|
else
|
|
{
|
|
ERR("failed to load string %p\n", dwTypeData);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
mii.dwTypeData = (LPWSTR)dwTypeData;
|
|
mii.fState = fState;
|
|
}
|
|
|
|
mii.wID = wID;
|
|
mii.fType = fType;
|
|
InsertMenuItemW(hMenu, indexMenu, fByPosition, &mii);
|
|
}
|
|
|
|
UINT
|
|
CDefaultContextMenu::BuildShellItemContextMenu(
|
|
HMENU hMenu,
|
|
UINT iIdCmdFirst,
|
|
UINT iIdCmdLast,
|
|
UINT uFlags)
|
|
{
|
|
HKEY hKey;
|
|
HRESULT hr;
|
|
|
|
TRACE("BuildShellItemContextMenu entered\n");
|
|
ASSERT(m_Dcm.cidl >= 1);
|
|
|
|
STRRET strFile;
|
|
hr = m_Dcm.psf->GetDisplayNameOf(m_Dcm.apidl[0], SHGDN_FORPARSING, &strFile);
|
|
if (hr == S_OK)
|
|
{
|
|
WCHAR wszPath[MAX_PATH];
|
|
hr = StrRetToBufW(&strFile, m_Dcm.apidl[0], wszPath, _countof(wszPath));
|
|
if (hr == S_OK)
|
|
{
|
|
LPCWSTR pwszExt = PathFindExtensionW(wszPath);
|
|
if (pwszExt[0])
|
|
{
|
|
/* enumerate dynamic/static for a given file class */
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
/* add static verbs */
|
|
AddStaticEntryForFileClass(pwszExt);
|
|
|
|
/* load dynamic extensions from file extension key */
|
|
EnumerateDynamicContextHandlerForKey(hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
WCHAR wszTemp[40];
|
|
DWORD dwSize = sizeof(wszTemp);
|
|
if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, NULL, RRF_RT_REG_SZ, NULL, wszTemp, &dwSize) == ERROR_SUCCESS)
|
|
{
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszTemp, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
/* add static verbs from progid key */
|
|
AddStaticEntryForFileClass(wszTemp);
|
|
|
|
/* load dynamic extensions from progid key */
|
|
EnumerateDynamicContextHandlerForKey(hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"*", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
/* load default extensions */
|
|
EnumerateDynamicContextHandlerForKey(hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
ERR("GetDisplayNameOf failed: %x\n", hr);
|
|
|
|
GUID *pGuid = _ILGetGUIDPointer(m_Dcm.apidl[0]);
|
|
if (pGuid)
|
|
{
|
|
LPOLESTR pwszCLSID;
|
|
WCHAR buffer[60];
|
|
|
|
wcscpy(buffer, L"CLSID\\");
|
|
hr = StringFromCLSID(*pGuid, &pwszCLSID);
|
|
if (hr == S_OK)
|
|
{
|
|
wcscpy(&buffer[6], pwszCLSID);
|
|
TRACE("buffer %s\n", debugstr_w(buffer));
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
EnumerateDynamicContextHandlerForKey(hKey);
|
|
AddStaticEntryForFileClass(buffer);
|
|
RegCloseKey(hKey);
|
|
}
|
|
CoTaskMemFree(pwszCLSID);
|
|
}
|
|
}
|
|
|
|
if (_ILIsDrive(m_Dcm.apidl[0]))
|
|
{
|
|
AddStaticEntryForFileClass(L"Drive");
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Drive", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
EnumerateDynamicContextHandlerForKey(hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
}
|
|
|
|
/* add static actions */
|
|
SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
|
|
hr = m_Dcm.psf->GetAttributesOf(m_Dcm.cidl, m_Dcm.apidl, &rfg);
|
|
if (FAILED(hr))
|
|
{
|
|
ERR("GetAttributesOf failed: %x\n", hr);
|
|
rfg = 0;
|
|
}
|
|
|
|
if (rfg & SFGAO_FOLDER)
|
|
{
|
|
/* add the default verbs open / explore */
|
|
AddStaticEntryForFileClass(L"Folder");
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Folder", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
EnumerateDynamicContextHandlerForKey(hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
/* Directory is only loaded for real filesystem directories */
|
|
if (_ILIsFolder(m_Dcm.apidl[0]))
|
|
{
|
|
AddStaticEntryForFileClass(L"Directory");
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
EnumerateDynamicContextHandlerForKey(hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* AllFilesystemObjects class is loaded only for files and directories */
|
|
if (_ILIsFolder(m_Dcm.apidl[0]) || _ILIsValue(m_Dcm.apidl[0]))
|
|
{
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"AllFilesystemObjects", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
/* sendto service is registered here */
|
|
EnumerateDynamicContextHandlerForKey(hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
/* add static context menu handlers */
|
|
UINT IndexMenu = AddStaticContextMenusToMenu(hMenu, 0);
|
|
|
|
/* now process dynamic context menu handlers */
|
|
BOOL bAddSep = FALSE;
|
|
IndexMenu = InsertMenuItemsOfDynamicContextMenuExtension(hMenu, IndexMenu, iIdCmdFirst, iIdCmdLast);
|
|
TRACE("IndexMenu %d\n", IndexMenu);
|
|
|
|
if (_ILIsDrive(m_Dcm.apidl[0]))
|
|
{
|
|
/* The 'Format' option must be always available,
|
|
* thus it is not registered as a static shell extension */
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0x7ABC, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED);
|
|
bAddSep = TRUE;
|
|
}
|
|
|
|
BOOL bClipboardData = (HasClipboardData() && (rfg & SFGAO_FILESYSTEM));
|
|
if (rfg & (SFGAO_CANCOPY | SFGAO_CANMOVE) || bClipboardData)
|
|
{
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
|
|
if (rfg & SFGAO_CANMOVE)
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_CUT, MFT_STRING, MAKEINTRESOURCEW(IDS_CUT), MFS_ENABLED);
|
|
if (rfg & SFGAO_CANCOPY)
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_COPY, MFT_STRING, MAKEINTRESOURCEW(IDS_COPY), MFS_ENABLED);
|
|
if (bClipboardData)
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_INSERT, MFT_STRING, MAKEINTRESOURCEW(IDS_INSERT), MFS_ENABLED);
|
|
|
|
bAddSep = TRUE;
|
|
}
|
|
|
|
if (rfg & SFGAO_CANLINK)
|
|
{
|
|
bAddSep = FALSE;
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_CREATELINK, MFT_STRING, MAKEINTRESOURCEW(IDS_CREATELINK), MFS_ENABLED);
|
|
}
|
|
|
|
if (rfg & SFGAO_CANDELETE)
|
|
{
|
|
if (bAddSep)
|
|
{
|
|
bAddSep = FALSE;
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
|
|
}
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_DELETE, MFT_STRING, MAKEINTRESOURCEW(IDS_DELETE), MFS_ENABLED);
|
|
}
|
|
|
|
if (rfg & SFGAO_CANRENAME)
|
|
{
|
|
if (bAddSep)
|
|
{
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
|
|
}
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_RENAME, MFT_STRING, MAKEINTRESOURCEW(IDS_RENAME), MFS_ENABLED);
|
|
bAddSep = TRUE;
|
|
}
|
|
|
|
if (rfg & SFGAO_HASPROPSHEET)
|
|
{
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
|
|
_InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
|
|
}
|
|
|
|
return iIdCmdLast;
|
|
}
|
|
|
|
HRESULT
|
|
WINAPI
|
|
CDefaultContextMenu::QueryContextMenu(
|
|
HMENU hMenu,
|
|
UINT IndexMenu,
|
|
UINT idCmdFirst,
|
|
UINT idCmdLast,
|
|
UINT uFlags)
|
|
{
|
|
if (m_Dcm.cidl)
|
|
idCmdFirst = BuildShellItemContextMenu(hMenu, idCmdFirst, idCmdLast, uFlags);
|
|
else
|
|
idCmdFirst = BuildBackgroundContextMenu(hMenu, idCmdFirst, idCmdLast, uFlags);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi, BOOL bRefresh)
|
|
{
|
|
/* Note: CWM_GETISHELLBROWSER returns not referenced object */
|
|
LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
|
|
if (!lpSB)
|
|
return E_FAIL;
|
|
|
|
LPSHELLVIEW lpSV = NULL;
|
|
if (FAILED(lpSB->QueryActiveShellView(&lpSV)))
|
|
return E_FAIL;
|
|
|
|
if (LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_REFRESH || bRefresh)
|
|
lpSV->Refresh();
|
|
else
|
|
{
|
|
HWND hwndSV = NULL;
|
|
if (SUCCEEDED(lpSV->GetWindow(&hwndSV)))
|
|
SendMessageW(hwndSV, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0);
|
|
}
|
|
|
|
lpSV->Release();
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CDefaultContextMenu::DoPaste(
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
HRESULT hr;
|
|
|
|
IDataObject *pda;
|
|
if (OleGetClipboard(&pda) != S_OK)
|
|
return E_FAIL;
|
|
|
|
STGMEDIUM medium;
|
|
FORMATETC formatetc;
|
|
InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
|
|
hr = pda->GetData(&formatetc, &medium);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
pda->Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* lock the handle */
|
|
LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
|
|
if (!lpcida)
|
|
{
|
|
ReleaseStgMedium(&medium);
|
|
pda->Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* convert the data into pidl */
|
|
LPITEMIDLIST pidl;
|
|
LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
|
|
|
|
if (!apidl)
|
|
return E_FAIL;
|
|
|
|
IShellFolder *psfDesktop;
|
|
if (FAILED(SHGetDesktopFolder(&psfDesktop)))
|
|
{
|
|
SHFree(pidl);
|
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
ReleaseStgMedium(&medium);
|
|
pda->Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* Find source folder */
|
|
IShellFolder *psfFrom = NULL;
|
|
if (_ILIsDesktop(pidl))
|
|
{
|
|
/* use desktop shellfolder */
|
|
psfFrom = psfDesktop;
|
|
}
|
|
else if (FAILED(psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfFrom)))
|
|
{
|
|
ERR("no IShellFolder\n");
|
|
|
|
psfDesktop->Release();
|
|
SHFree(pidl);
|
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
ReleaseStgMedium(&medium);
|
|
pda->Release();
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* Find target folder */
|
|
IShellFolder *psfTarget = NULL;
|
|
if (m_Dcm.cidl)
|
|
{
|
|
psfDesktop->Release();
|
|
hr = m_Dcm.psf->BindToObject(m_Dcm.apidl[0], NULL, IID_IShellFolder, (LPVOID*)&psfTarget);
|
|
}
|
|
else
|
|
{
|
|
IPersistFolder2 *ppf2 = NULL;
|
|
LPITEMIDLIST pidl;
|
|
|
|
/* cidl is zero due to explorer view */
|
|
hr = m_Dcm.psf->QueryInterface(IID_IPersistFolder2, (LPVOID *) &ppf2);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = ppf2->GetCurFolder(&pidl);
|
|
ppf2->Release();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (_ILIsDesktop(pidl))
|
|
{
|
|
/* use desktop shellfolder */
|
|
psfTarget = psfDesktop;
|
|
}
|
|
else
|
|
{
|
|
/* retrieve target desktop folder */
|
|
hr = psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfTarget);
|
|
}
|
|
TRACE("psfTarget %x %p, Desktop %u\n", hr, psfTarget, _ILIsDesktop(pidl));
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
ERR("no IShellFolder\n");
|
|
|
|
psfFrom->Release();
|
|
SHFree(pidl);
|
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
ReleaseStgMedium(&medium);
|
|
pda->Release();
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* get source and destination shellfolder */
|
|
ISFHelper *psfhlpdst;
|
|
if (FAILED(psfTarget->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpdst)))
|
|
{
|
|
ERR("no IID_ISFHelper for destination\n");
|
|
|
|
psfFrom->Release();
|
|
psfTarget->Release();
|
|
SHFree(pidl);
|
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
ReleaseStgMedium(&medium);
|
|
pda->Release();
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
ISFHelper *psfhlpsrc;
|
|
if (FAILED(psfFrom->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpsrc)))
|
|
{
|
|
ERR("no IID_ISFHelper for source\n");
|
|
|
|
psfhlpdst->Release();
|
|
psfFrom->Release();
|
|
psfTarget->Release();
|
|
SHFree(pidl);
|
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
ReleaseStgMedium(&medium);
|
|
pda->Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* FIXXME
|
|
* do we want to perform a copy or move ???
|
|
*/
|
|
hr = psfhlpdst->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl);
|
|
|
|
psfhlpdst->Release();
|
|
psfhlpsrc->Release();
|
|
psfFrom->Release();
|
|
psfTarget->Release();
|
|
SHFree(pidl);
|
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
ReleaseStgMedium(&medium);
|
|
pda->Release();
|
|
TRACE("CP result %x\n", hr);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CDefaultContextMenu::DoOpenOrExplore(
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return E_FAIL;
|
|
}
|
|
|
|
BOOL
|
|
GetUniqueFileName(LPWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut)
|
|
{
|
|
WCHAR wszLink[40];
|
|
|
|
if (!bShortcut)
|
|
{
|
|
if (!LoadStringW(shell32_hInstance, IDS_LNK_FILE, wszLink, _countof(wszLink)))
|
|
wszLink[0] = L'\0';
|
|
}
|
|
|
|
if (!bShortcut)
|
|
swprintf(pwszTarget, L"%s%s%s", wszLink, pwszBasePath, pwszExt);
|
|
else
|
|
swprintf(pwszTarget, L"%s%s", pwszBasePath, pwszExt);
|
|
|
|
for (UINT i = 2; PathFileExistsW(pwszTarget); ++i)
|
|
{
|
|
if (!bShortcut)
|
|
swprintf(pwszTarget, L"%s%s (%u)%s", wszLink, pwszBasePath, i, pwszExt);
|
|
else
|
|
swprintf(pwszTarget, L"%s (%u)%s", pwszBasePath, i, pwszExt);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CDefaultContextMenu::DoCreateLink(
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
WCHAR wszTarget[MAX_PATH];
|
|
IPersistFile *ppf;
|
|
HRESULT hr;
|
|
STRRET strFile;
|
|
|
|
if (m_Dcm.psf->GetDisplayNameOf(m_Dcm.apidl[0], SHGDN_FORPARSING, &strFile) != S_OK)
|
|
{
|
|
ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
WCHAR wszPath[MAX_PATH];
|
|
if (StrRetToBufW(&strFile, m_Dcm.apidl[0], wszPath, _countof(wszPath)) != S_OK)
|
|
return E_FAIL;
|
|
|
|
LPWSTR pwszExt = PathFindExtensionW(wszPath);
|
|
|
|
if (!wcsicmp(pwszExt, L".lnk"))
|
|
{
|
|
if (!GetUniqueFileName(wszPath, pwszExt, wszTarget, TRUE))
|
|
return E_FAIL;
|
|
|
|
hr = IShellLink_ConstructFromFile(NULL, IID_IPersistFile, m_Dcm.apidl[0], (LPVOID*)&ppf);
|
|
if (hr != S_OK)
|
|
return hr;
|
|
|
|
hr = ppf->Save(wszTarget, FALSE);
|
|
ppf->Release();
|
|
NotifyShellViewWindow(lpcmi, TRUE);
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
if (!GetUniqueFileName(wszPath, L".lnk", wszTarget, TRUE))
|
|
return E_FAIL;
|
|
|
|
IShellLinkW *pLink;
|
|
hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_IShellLinkW, (void**)&pLink);
|
|
if (hr != S_OK)
|
|
return hr;
|
|
|
|
WCHAR szDirPath[MAX_PATH], *pwszFile;
|
|
GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile);
|
|
if (pwszFile) pwszFile[0] = 0;
|
|
|
|
if (SUCCEEDED(pLink->SetPath(wszPath)) &&
|
|
SUCCEEDED(pLink->SetWorkingDirectory(szDirPath)))
|
|
{
|
|
if (SUCCEEDED(pLink->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf)))
|
|
{
|
|
hr = ppf->Save(wszTarget, TRUE);
|
|
ppf->Release();
|
|
}
|
|
}
|
|
pLink->Release();
|
|
NotifyShellViewWindow(lpcmi, TRUE);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CDefaultContextMenu::DoDelete(
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
STRRET strTemp;
|
|
HRESULT hr = m_Dcm.psf->GetDisplayNameOf(m_Dcm.apidl[0], SHGDN_FORPARSING, &strTemp);
|
|
if(hr != S_OK)
|
|
{
|
|
ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr);
|
|
return hr;
|
|
}
|
|
|
|
WCHAR wszPath[MAX_PATH];
|
|
hr = StrRetToBufW(&strTemp, m_Dcm.apidl[0], wszPath, _countof(wszPath));
|
|
if (hr != S_OK)
|
|
{
|
|
ERR("StrRetToBufW failed with %x\n", hr);
|
|
return hr;
|
|
}
|
|
|
|
/* Only keep the base path */
|
|
LPWSTR pwszFilename = PathFindFileNameW(wszPath);
|
|
*pwszFilename = L'\0';
|
|
|
|
/* Build paths list */
|
|
LPWSTR pwszPaths = BuildPathsList(wszPath, m_Dcm.cidl, m_Dcm.apidl);
|
|
if (!pwszPaths)
|
|
return E_FAIL;
|
|
|
|
/* Delete them */
|
|
SHFILEOPSTRUCTW FileOp;
|
|
ZeroMemory(&FileOp, sizeof(FileOp));
|
|
FileOp.hwnd = GetActiveWindow();
|
|
FileOp.wFunc = FO_DELETE;
|
|
FileOp.pFrom = pwszPaths;
|
|
FileOp.fFlags = FOF_ALLOWUNDO;
|
|
|
|
if (SHFileOperationW(&FileOp) != 0)
|
|
{
|
|
ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(pwszPaths));
|
|
return S_OK;
|
|
}
|
|
|
|
/* Get the active IShellView */
|
|
LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageW(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
|
|
if (lpSB)
|
|
{
|
|
/* Is the treeview focused */
|
|
HWND hwnd;
|
|
if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwnd)))
|
|
{
|
|
/* Remove selected items from treeview */
|
|
HTREEITEM hItem = TreeView_GetSelection(hwnd);
|
|
if (hItem)
|
|
(void)TreeView_DeleteItem(hwnd, hItem);
|
|
}
|
|
}
|
|
NotifyShellViewWindow(lpcmi, TRUE);
|
|
|
|
HeapFree(GetProcessHeap(), 0, pwszPaths);
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CDefaultContextMenu::DoCopyOrCut(
|
|
LPCMINVOKECOMMANDINFO lpcmi,
|
|
BOOL bCopy)
|
|
{
|
|
LPDATAOBJECT pDataObj;
|
|
HRESULT hr;
|
|
|
|
if (SUCCEEDED(SHCreateDataObject(m_Dcm.pidlFolder, m_Dcm.cidl, m_Dcm.apidl, NULL, IID_IDataObject, (void**)&pDataObj)))
|
|
{
|
|
hr = OleSetClipboard(pDataObj);
|
|
pDataObj->Release();
|
|
return hr;
|
|
}
|
|
|
|
/* Note: CWM_GETISHELLBROWSER returns not referenced object */
|
|
LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
|
|
if (!lpSB)
|
|
{
|
|
ERR("failed to get shellbrowser\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
LPSHELLVIEW lpSV;
|
|
hr = lpSB->QueryActiveShellView(&lpSV);
|
|
if (FAILED(hr))
|
|
{
|
|
ERR("failed to query the active shellview\n");
|
|
return hr;
|
|
}
|
|
|
|
hr = lpSV->GetItemObject(SVGIO_SELECTION, IID_IDataObject, (LPVOID*)&pDataObj);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = OleSetClipboard(pDataObj);
|
|
if (FAILED(hr))
|
|
ERR("OleSetClipboard failed");
|
|
pDataObj->Release();
|
|
} else
|
|
ERR("failed to get item object\n");
|
|
|
|
lpSV->Release();
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CDefaultContextMenu::DoRename(
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
/* get the active IShellView. Note: CWM_GETISHELLBROWSER returns not referenced object */
|
|
LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
|
|
if (!lpSB)
|
|
{
|
|
ERR("CWM_GETISHELLBROWSER failed\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* is the treeview focused */
|
|
HWND hwnd;
|
|
if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwnd)))
|
|
{
|
|
HTREEITEM hItem = TreeView_GetSelection(hwnd);
|
|
if (hItem)
|
|
(void)TreeView_EditLabel(hwnd, hItem);
|
|
}
|
|
|
|
LPSHELLVIEW lpSV;
|
|
HRESULT hr = lpSB->QueryActiveShellView(&lpSV);
|
|
if (FAILED(hr))
|
|
{
|
|
ERR("CWM_GETISHELLBROWSER failed\n");
|
|
return hr;
|
|
}
|
|
|
|
lpSV->SelectItem(m_Dcm.apidl[0],
|
|
SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_SELECT);
|
|
lpSV->Release();
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CDefaultContextMenu::DoProperties(
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
const ITEMIDLIST *pidlParent = m_Dcm.pidlFolder, *pidlChild;
|
|
|
|
if (!pidlParent)
|
|
{
|
|
IPersistFolder2 *pf;
|
|
|
|
/* pidlFolder is optional */
|
|
if (SUCCEEDED(m_Dcm.psf->QueryInterface(IID_IPersistFolder2, (PVOID*)&pf)))
|
|
{
|
|
pf->GetCurFolder((_ITEMIDLIST**)&pidlParent);
|
|
pf->Release();
|
|
}
|
|
}
|
|
|
|
if (m_Dcm.cidl > 0)
|
|
pidlChild = m_Dcm.apidl[0];
|
|
else
|
|
{
|
|
/* Set pidlChild to last pidl of current folder */
|
|
if (pidlParent == m_Dcm.pidlFolder)
|
|
pidlParent = (ITEMIDLIST*)ILClone(pidlParent);
|
|
|
|
pidlChild = (ITEMIDLIST*)ILClone(ILFindLastID(pidlParent));
|
|
ILRemoveLastID((ITEMIDLIST*)pidlParent);
|
|
}
|
|
|
|
if (_ILIsMyComputer(pidlChild))
|
|
{
|
|
if (32 >= (UINT)ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL, NULL, SW_SHOWNORMAL))
|
|
hr = E_FAIL;
|
|
}
|
|
else if (_ILIsDesktop(pidlChild))
|
|
{
|
|
if (32 >= (UINT)ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL))
|
|
hr = E_FAIL;
|
|
}
|
|
else if (_ILIsDrive(pidlChild))
|
|
{
|
|
WCHAR wszBuf[MAX_PATH];
|
|
ILGetDisplayName(pidlChild, wszBuf);
|
|
if (!SH_ShowDriveProperties(wszBuf, pidlParent, &pidlChild))
|
|
hr = E_FAIL;
|
|
}
|
|
else if (_ILIsNetHood(pidlChild))
|
|
{
|
|
// FIXME path!
|
|
if (32 >= (UINT)ShellExecuteW(NULL, L"open", L"explorer.exe",
|
|
L"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
|
|
NULL, SW_SHOWDEFAULT))
|
|
hr = E_FAIL;
|
|
}
|
|
else if (_ILIsBitBucket(pidlChild))
|
|
{
|
|
/* FIXME: detect the drive path of bitbucket if appropiate */
|
|
if(!SH_ShowRecycleBinProperties(L'C'))
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
if (m_Dcm.cidl > 1)
|
|
WARN("SHMultiFileProperties is not yet implemented\n");
|
|
|
|
STRRET strFile;
|
|
hr = m_Dcm.psf->GetDisplayNameOf(pidlChild, SHGDN_FORPARSING, &strFile);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR wszBuf[MAX_PATH];
|
|
hr = StrRetToBufW(&strFile, pidlChild, wszBuf, _countof(wszBuf));
|
|
if (SUCCEEDED(hr))
|
|
hr = SH_ShowPropertiesDialog(wszBuf, pidlParent, &pidlChild);
|
|
else
|
|
ERR("StrRetToBufW failed\n");
|
|
}
|
|
else
|
|
ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
|
|
}
|
|
|
|
/* Free allocated PIDLs */
|
|
if (pidlParent != m_Dcm.pidlFolder)
|
|
ILFree((ITEMIDLIST*)pidlParent);
|
|
if (m_Dcm.cidl < 1 || pidlChild != m_Dcm.apidl[0])
|
|
ILFree((ITEMIDLIST*)pidlChild);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CDefaultContextMenu::DoFormat(
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
char szDrive[8] = {0};
|
|
|
|
if (!_ILGetDrive(m_Dcm.apidl[0], szDrive, sizeof(szDrive)))
|
|
{
|
|
ERR("pidl is not a drive\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
SHFormatDrive(lpcmi->hwnd, szDrive[0] - 'A', SHFMT_ID_DEFAULT, 0);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CDefaultContextMenu::DoDynamicShellExtensions(
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
UINT idCmd = LOWORD(lpcmi->lpVerb);
|
|
PDynamicShellEntry pEntry = m_pDynamicEntries;
|
|
|
|
TRACE("verb %p first %x last %x", lpcmi->lpVerb, m_iIdSHEFirst, m_iIdSHELast);
|
|
|
|
while(pEntry && idCmd > pEntry->iIdCmdFirst + pEntry->NumIds)
|
|
pEntry = pEntry->pNext;
|
|
|
|
if (!pEntry)
|
|
return E_FAIL;
|
|
|
|
if (idCmd >= pEntry->iIdCmdFirst && idCmd <= pEntry->iIdCmdFirst + pEntry->NumIds)
|
|
{
|
|
/* invoke the dynamic context menu */
|
|
lpcmi->lpVerb = MAKEINTRESOURCEA(idCmd - pEntry->iIdCmdFirst);
|
|
return pEntry->pCM->InvokeCommand(lpcmi);
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
DWORD
|
|
CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi, PStaticShellEntry pEntry)
|
|
{
|
|
LPSHELLBROWSER lpSB;
|
|
HWND hwndTree;
|
|
LPWSTR FlagsName;
|
|
WCHAR wszKey[256];
|
|
HRESULT hr;
|
|
DWORD wFlags;
|
|
DWORD cbVerb;
|
|
|
|
/* Get a pointer to the shell browser */
|
|
lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
|
|
if (lpSB == NULL)
|
|
return 0;
|
|
|
|
/* See if we are in Explore or Browse mode. If the browser's tree is present, we are in Explore mode.*/
|
|
if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwndTree)) && hwndTree)
|
|
FlagsName = L"ExplorerFlags";
|
|
else
|
|
FlagsName = L"BrowserFlags";
|
|
|
|
/* Try to get the flag from the verb */
|
|
hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"%s\\shell\\%s", pEntry->szClass, pEntry->szVerb);
|
|
if (!SUCCEEDED(hr))
|
|
return 0;
|
|
|
|
cbVerb = sizeof(wFlags);
|
|
if (RegGetValueW(HKEY_CLASSES_ROOT, wszKey, FlagsName, RRF_RT_REG_DWORD, NULL, &wFlags, &cbVerb) == ERROR_SUCCESS)
|
|
{
|
|
return wFlags;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
HRESULT
|
|
CDefaultContextMenu::TryToBrowse(
|
|
LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, DWORD wFlags)
|
|
{
|
|
LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageW(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
|
|
HRESULT hr;
|
|
|
|
if (lpSB == NULL)
|
|
return E_FAIL;
|
|
|
|
hr = lpSB->BrowseObject(ILCombine(m_Dcm.pidlFolder, pidl), wFlags);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, PStaticShellEntry pEntry)
|
|
{
|
|
HRESULT hr;
|
|
STRRET strFile;
|
|
|
|
hr = m_Dcm.psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strFile);
|
|
if (hr != S_OK)
|
|
{
|
|
ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
|
|
return hr;
|
|
}
|
|
|
|
WCHAR wszPath[MAX_PATH];
|
|
hr = StrRetToBufW(&strFile, pidl, wszPath, MAX_PATH);
|
|
if (hr != S_OK)
|
|
return hr;
|
|
|
|
WCHAR wszDir[MAX_PATH];
|
|
wcscpy(wszDir, wszPath);
|
|
PathRemoveFileSpec(wszDir);
|
|
|
|
SHELLEXECUTEINFOW sei;
|
|
ZeroMemory(&sei, sizeof(sei));
|
|
sei.cbSize = sizeof(sei);
|
|
sei.hwnd = lpcmi->hwnd;
|
|
sei.nShow = SW_SHOWNORMAL;
|
|
sei.lpVerb = pEntry->szVerb;
|
|
sei.lpFile = wszPath;
|
|
sei.lpDirectory = wszDir;
|
|
ShellExecuteExW(&sei);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CDefaultContextMenu::DoStaticShellExtensions(
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
PStaticShellEntry pEntry = m_pStaticEntries;
|
|
INT iCmd = LOWORD(lpcmi->lpVerb) - m_iIdSCMFirst;
|
|
HRESULT hr;
|
|
UINT i;
|
|
|
|
while (pEntry && (iCmd--) > 0)
|
|
pEntry = pEntry->pNext;
|
|
|
|
if (iCmd > 0)
|
|
return E_FAIL;
|
|
|
|
/* Get the browse flags to see if we need to browse */
|
|
DWORD wFlags = BrowserFlagsFromVerb(lpcmi, pEntry);
|
|
BOOL bBrowsed = FALSE;
|
|
|
|
for (i=0; i < m_Dcm.cidl; i++)
|
|
{
|
|
/* Check if we need to browse */
|
|
if (wFlags > 0)
|
|
{
|
|
/* In xp if we have browsed, we don't open any more folders .
|
|
* In win7 we browse to the first folder we find and
|
|
* open new windows fo for each of the rest of the folders */
|
|
if (bBrowsed)
|
|
continue;
|
|
|
|
hr = TryToBrowse(lpcmi, m_Dcm.apidl[i], wFlags);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
bBrowsed = TRUE;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
InvokePidl(lpcmi, m_Dcm.apidl[i], pEntry);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
WINAPI
|
|
CDefaultContextMenu::InvokeCommand(
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
switch(LOWORD(lpcmi->lpVerb))
|
|
{
|
|
case FCIDM_SHVIEW_BIGICON:
|
|
case FCIDM_SHVIEW_SMALLICON:
|
|
case FCIDM_SHVIEW_LISTVIEW:
|
|
case FCIDM_SHVIEW_REPORTVIEW:
|
|
case 0x30: /* FIX IDS in resource files */
|
|
case 0x31:
|
|
case 0x32:
|
|
case 0x33:
|
|
case FCIDM_SHVIEW_AUTOARRANGE:
|
|
case FCIDM_SHVIEW_SNAPTOGRID:
|
|
case FCIDM_SHVIEW_REFRESH:
|
|
return NotifyShellViewWindow(lpcmi, FALSE);
|
|
case FCIDM_SHVIEW_INSERT:
|
|
case FCIDM_SHVIEW_INSERTLINK:
|
|
return DoPaste(lpcmi);
|
|
case FCIDM_SHVIEW_OPEN:
|
|
case FCIDM_SHVIEW_EXPLORE:
|
|
return DoOpenOrExplore(lpcmi);
|
|
case FCIDM_SHVIEW_COPY:
|
|
case FCIDM_SHVIEW_CUT:
|
|
return DoCopyOrCut(lpcmi, LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_COPY);
|
|
case FCIDM_SHVIEW_CREATELINK:
|
|
return DoCreateLink(lpcmi);
|
|
case FCIDM_SHVIEW_DELETE:
|
|
return DoDelete(lpcmi);
|
|
case FCIDM_SHVIEW_RENAME:
|
|
return DoRename(lpcmi);
|
|
case FCIDM_SHVIEW_PROPERTIES:
|
|
return DoProperties(lpcmi);
|
|
case 0x7ABC:
|
|
return DoFormat(lpcmi);
|
|
}
|
|
|
|
if (m_iIdSHEFirst && m_iIdSHELast)
|
|
{
|
|
if (LOWORD(lpcmi->lpVerb) >= m_iIdSHEFirst && LOWORD(lpcmi->lpVerb) <= m_iIdSHELast)
|
|
return DoDynamicShellExtensions(lpcmi);
|
|
}
|
|
|
|
if (m_iIdSCMFirst && m_iIdSCMLast)
|
|
{
|
|
if (LOWORD(lpcmi->lpVerb) >= m_iIdSCMFirst && LOWORD(lpcmi->lpVerb) <= m_iIdSCMLast)
|
|
return DoStaticShellExtensions(lpcmi);
|
|
}
|
|
|
|
FIXME("Unhandled Verb %xl\n", LOWORD(lpcmi->lpVerb));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
HRESULT
|
|
WINAPI
|
|
CDefaultContextMenu::GetCommandString(
|
|
UINT_PTR idCommand,
|
|
UINT uFlags,
|
|
UINT* lpReserved,
|
|
LPSTR lpszName,
|
|
UINT uMaxNameLen)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
WINAPI
|
|
CDefaultContextMenu::HandleMenuMsg(
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
IDefaultContextMenu_Constructor(
|
|
const DEFCONTEXTMENU *pdcm,
|
|
REFIID riid,
|
|
void **ppv)
|
|
{
|
|
if (ppv == NULL)
|
|
return E_POINTER;
|
|
*ppv = NULL;
|
|
|
|
CComObject<CDefaultContextMenu> *pCM;
|
|
HRESULT hr = CComObject<CDefaultContextMenu>::CreateInstance(&pCM);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
pCM->AddRef(); // CreateInstance returns object with 0 ref count */
|
|
|
|
CComPtr<IUnknown> pResult;
|
|
hr = pCM->QueryInterface(riid, (void **)&pResult);
|
|
if (FAILED(hr))
|
|
{
|
|
pCM->Release();
|
|
return hr;
|
|
}
|
|
|
|
hr = pCM->Initialize(pdcm);
|
|
if (FAILED(hr))
|
|
{
|
|
pCM->Release();
|
|
return hr;
|
|
}
|
|
|
|
*ppv = pResult.Detach();
|
|
pCM->Release();
|
|
TRACE("This(%p) cidl %u\n", *ppv, pdcm->cidl);
|
|
return S_OK;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* SHCreateDefaultContextMenu [SHELL32.325] Vista API
|
|
*
|
|
*/
|
|
|
|
HRESULT
|
|
WINAPI
|
|
SHCreateDefaultContextMenu(
|
|
const DEFCONTEXTMENU *pdcm,
|
|
REFIID riid,
|
|
void **ppv)
|
|
{
|
|
*ppv = NULL;
|
|
HRESULT hr = IDefaultContextMenu_Constructor(pdcm, riid, ppv);
|
|
if (FAILED(hr))
|
|
ERR("IDefaultContextMenu_Constructor failed: %x\n", hr);
|
|
TRACE("pcm %p hr %x\n", pdcm, hr);
|
|
return hr;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* CDefFolderMenu_Create2 [SHELL32.701]
|
|
*
|
|
*/
|
|
|
|
HRESULT
|
|
WINAPI
|
|
CDefFolderMenu_Create2(
|
|
LPCITEMIDLIST pidlFolder,
|
|
HWND hwnd,
|
|
UINT cidl,
|
|
LPCITEMIDLIST *apidl,
|
|
IShellFolder *psf,
|
|
LPFNDFMCALLBACK lpfn,
|
|
UINT nKeys,
|
|
const HKEY *ahkeyClsKeys,
|
|
IContextMenu **ppcm)
|
|
{
|
|
DEFCONTEXTMENU pdcm;
|
|
pdcm.hwnd = hwnd;
|
|
pdcm.pcmcb = NULL;
|
|
pdcm.pidlFolder = pidlFolder;
|
|
pdcm.psf = psf;
|
|
pdcm.cidl = cidl;
|
|
pdcm.apidl = apidl;
|
|
pdcm.punkAssociationInfo = NULL;
|
|
pdcm.cKeys = nKeys;
|
|
pdcm.aKeys = ahkeyClsKeys;
|
|
|
|
HRESULT hr = SHCreateDefaultContextMenu(&pdcm, IID_IContextMenu, (void**)ppcm);
|
|
return hr;
|
|
}
|
|
|