mirror of
https://github.com/reactos/reactos.git
synced 2024-11-05 22:26:39 +00:00
c424146e2c
svn path=/branches/cmake-bringup/; revision=48236
1785 lines
48 KiB
C
1785 lines
48 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)
|
|
*/
|
|
|
|
#include <precomp.h>
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(dmenu);
|
|
|
|
typedef struct _DynamicShellEntry_
|
|
{
|
|
UINT iIdCmdFirst;
|
|
UINT NumIds;
|
|
CLSID ClassID;
|
|
IContextMenu * CMenu;
|
|
struct _DynamicShellEntry_ * Next;
|
|
}DynamicShellEntry, *PDynamicShellEntry;
|
|
|
|
typedef struct _StaticShellEntry_
|
|
{
|
|
LPWSTR szVerb;
|
|
LPWSTR szClass;
|
|
struct _StaticShellEntry_ * Next;
|
|
}StaticShellEntry, *PStaticShellEntry;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
const IContextMenu2Vtbl *lpVtbl;
|
|
LONG ref;
|
|
DEFCONTEXTMENU dcm;
|
|
IDataObject * pDataObj;
|
|
DWORD bGroupPolicyActive;
|
|
PDynamicShellEntry dhead; /* first dynamic shell extension entry */
|
|
UINT iIdSHEFirst; /* first used id */
|
|
UINT iIdSHELast; /* last used id */
|
|
PStaticShellEntry shead; /* first static shell extension entry */
|
|
UINT iIdSCMFirst; /* first static used id */
|
|
UINT iIdSCMLast; /* last static used id */
|
|
}IDefaultContextMenuImpl, *LPIDefaultContextMenuImpl;
|
|
|
|
static LPIDefaultContextMenuImpl __inline impl_from_IContextMenu( IContextMenu2 *iface )
|
|
{
|
|
return (LPIDefaultContextMenuImpl)((char*)iface - FIELD_OFFSET(IDefaultContextMenuImpl, lpVtbl));
|
|
}
|
|
|
|
VOID INewItem_SetCurrentShellFolder(IShellFolder * psfParent); // HACK
|
|
WCHAR *build_paths_list(LPCWSTR wszBasePath, int cidl, LPCITEMIDLIST *pidls);
|
|
|
|
static
|
|
HRESULT
|
|
WINAPI
|
|
IDefaultContextMenu_fnQueryInterface(
|
|
IContextMenu2 *iface,
|
|
REFIID riid,
|
|
LPVOID *ppvObj)
|
|
{
|
|
IDefaultContextMenuImpl *This = (IDefaultContextMenuImpl *)iface;
|
|
|
|
TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
|
|
|
|
*ppvObj = NULL;
|
|
|
|
if(IsEqualIID(riid, &IID_IUnknown) ||
|
|
IsEqualIID(riid, &IID_IContextMenu) ||
|
|
IsEqualIID(riid, &IID_IContextMenu2))
|
|
{
|
|
*ppvObj = This;
|
|
}
|
|
|
|
if(*ppvObj)
|
|
{
|
|
IUnknown_AddRef((IUnknown*)*ppvObj);
|
|
TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
|
|
return S_OK;
|
|
}
|
|
TRACE("-- Interface: E_NOINTERFACE\n");
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
static
|
|
ULONG
|
|
WINAPI
|
|
IDefaultContextMenu_fnAddRef(
|
|
IContextMenu2 *iface)
|
|
{
|
|
IDefaultContextMenuImpl *This = (IDefaultContextMenuImpl *)iface;
|
|
ULONG refCount = InterlockedIncrement(&This->ref);
|
|
|
|
TRACE("(%p)->(count=%u)\n", This, refCount - 1);
|
|
|
|
return refCount;
|
|
}
|
|
|
|
static
|
|
ULONG
|
|
WINAPI
|
|
IDefaultContextMenu_fnRelease(
|
|
IContextMenu2 *iface)
|
|
{
|
|
PDynamicShellEntry dEntry, dNext;
|
|
PStaticShellEntry sEntry, sNext;
|
|
IDefaultContextMenuImpl *This = (IDefaultContextMenuImpl *)iface;
|
|
ULONG refCount = InterlockedDecrement(&This->ref);
|
|
|
|
TRACE("(%p)->(count=%u)\n", This, refCount + 1);
|
|
if (!refCount)
|
|
{
|
|
/* free dynamic shell extension entries */
|
|
dEntry = This->dhead;
|
|
while(dEntry)
|
|
{
|
|
dNext = dEntry->Next;
|
|
IContextMenu_Release(dEntry->CMenu);
|
|
HeapFree(GetProcessHeap(), 0, dEntry);
|
|
dEntry = dNext;
|
|
}
|
|
/* free static shell extension entries */
|
|
sEntry = This->shead;
|
|
while(sEntry)
|
|
{
|
|
sNext = sEntry->Next;
|
|
HeapFree(GetProcessHeap(), 0, sEntry->szClass);
|
|
HeapFree(GetProcessHeap(), 0, sEntry->szVerb);
|
|
HeapFree(GetProcessHeap(), 0, sEntry);
|
|
sEntry = sNext;
|
|
}
|
|
HeapFree(GetProcessHeap(),0,This);
|
|
}
|
|
|
|
return refCount;
|
|
}
|
|
|
|
static
|
|
void
|
|
SH_AddStaticEntry(IDefaultContextMenuImpl * This, WCHAR *szVerb, WCHAR * szClass)
|
|
{
|
|
PStaticShellEntry curEntry;
|
|
PStaticShellEntry lastEntry = NULL;
|
|
|
|
curEntry = This->shead;
|
|
while(curEntry)
|
|
{
|
|
if (!wcsicmp(curEntry->szVerb, szVerb))
|
|
{
|
|
/* entry already exists */
|
|
return;
|
|
}
|
|
lastEntry = curEntry;
|
|
curEntry = curEntry->Next;
|
|
}
|
|
|
|
TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb), debugstr_w(szClass));
|
|
|
|
curEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry));
|
|
if (curEntry)
|
|
{
|
|
curEntry->Next = NULL;
|
|
curEntry->szVerb = HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb)+1) * sizeof(WCHAR));
|
|
if (curEntry->szVerb)
|
|
wcscpy(curEntry->szVerb, szVerb);
|
|
curEntry->szClass = HeapAlloc(GetProcessHeap(), 0, (wcslen(szClass)+1) * sizeof(WCHAR));
|
|
if (curEntry->szClass)
|
|
wcscpy(curEntry->szClass, szClass);
|
|
}
|
|
|
|
if (!wcsicmp(szVerb, L"open"))
|
|
{
|
|
/* open verb is always inserted in front */
|
|
curEntry->Next = This->shead;
|
|
This->shead = curEntry;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
if (lastEntry)
|
|
{
|
|
lastEntry->Next = curEntry;
|
|
}
|
|
else
|
|
{
|
|
This->shead = curEntry;
|
|
}
|
|
}
|
|
|
|
static
|
|
void
|
|
SH_AddStaticEntryForKey(IDefaultContextMenuImpl * This, HKEY hKey, WCHAR * szClass)
|
|
{
|
|
LONG result;
|
|
DWORD dwIndex;
|
|
WCHAR szName[40];
|
|
DWORD dwName;
|
|
|
|
dwIndex = 0;
|
|
do
|
|
{
|
|
szName[0] = 0;
|
|
dwName = sizeof(szName) / sizeof(WCHAR);
|
|
result = RegEnumKeyExW(hKey, dwIndex, szName, &dwName, NULL, NULL, NULL, NULL);
|
|
szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0;
|
|
if (result == ERROR_SUCCESS)
|
|
{
|
|
SH_AddStaticEntry(This, szName, szClass);
|
|
}
|
|
dwIndex++;
|
|
}while(result == ERROR_SUCCESS);
|
|
}
|
|
|
|
static
|
|
void
|
|
SH_AddStaticEntryForFileClass(IDefaultContextMenuImpl * This, WCHAR * szExt)
|
|
{
|
|
WCHAR szBuffer[100];
|
|
HKEY hKey;
|
|
LONG result;
|
|
DWORD dwBuffer;
|
|
UINT Length;
|
|
static WCHAR szShell[] = L"\\shell";
|
|
static WCHAR szShellAssoc[] = L"SystemFileAssociations\\";
|
|
|
|
TRACE("SH_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;
|
|
SH_AddStaticEntryForKey(This, 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;
|
|
SH_AddStaticEntryForKey(This, 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[(sizeof(szShellAssoc)/sizeof(WCHAR))], &dwBuffer);
|
|
if (result == ERROR_SUCCESS)
|
|
{
|
|
Length = wcslen(&szBuffer[(sizeof(szShellAssoc)/sizeof(WCHAR))]) + (sizeof(szShellAssoc)/sizeof(WCHAR));
|
|
wcscat(&szBuffer[(sizeof(szShellAssoc)/sizeof(WCHAR))], 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;
|
|
SH_AddStaticEntryForKey(This, hKey, szBuffer);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
BOOL
|
|
HasClipboardData()
|
|
{
|
|
BOOL ret = FALSE;
|
|
IDataObject * pda;
|
|
|
|
if(SUCCEEDED(OleGetClipboard(&pda)))
|
|
{
|
|
STGMEDIUM medium;
|
|
FORMATETC formatetc;
|
|
|
|
TRACE("pda=%p\n", pda);
|
|
|
|
/* Set the FORMATETC structure*/
|
|
InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
|
|
if(SUCCEEDED(IDataObject_GetData(pda,&formatetc,&medium)))
|
|
{
|
|
ret = TRUE;
|
|
ReleaseStgMedium(&medium);
|
|
}
|
|
|
|
IDataObject_Release(pda);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
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
|
|
IsShellExtensionAlreadyLoaded(IDefaultContextMenuImpl * This, const CLSID * szClass)
|
|
{
|
|
PDynamicShellEntry curEntry = This->dhead;
|
|
|
|
while(curEntry)
|
|
{
|
|
if (!memcmp(&curEntry->ClassID, szClass, sizeof(CLSID)))
|
|
return TRUE;
|
|
curEntry = curEntry->Next;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static
|
|
HRESULT
|
|
SH_LoadDynamicContextMenuHandler(IDefaultContextMenuImpl * This, HKEY hKey, const CLSID * szClass, BOOL bExternalInit)
|
|
{
|
|
HRESULT hr;
|
|
IContextMenu * cmobj;
|
|
IShellExtInit *shext;
|
|
PDynamicShellEntry curEntry;
|
|
//WCHAR szTemp[100];
|
|
LPOLESTR pstr;
|
|
|
|
StringFromCLSID(szClass, &pstr);
|
|
|
|
TRACE("SH_LoadDynamicContextMenuHandler entered with This %p hKey %p szClass %s bExternalInit %u\n",This, hKey, wine_dbgstr_guid(szClass), bExternalInit);
|
|
//swprintf(szTemp, L"This %p hKey %p szClass %s bExternalInit %u", This, hKey, pstr, bExternalInit);
|
|
//MessageBoxW(NULL, szTemp, NULL, MB_OK);
|
|
|
|
if (IsShellExtensionAlreadyLoaded(This, szClass))
|
|
return S_OK;
|
|
|
|
hr = SHCoCreateInstance(NULL, szClass, NULL, &IID_IContextMenu, (void**)&cmobj);
|
|
if (hr != S_OK)
|
|
{
|
|
TRACE("SHCoCreateInstance failed %x\n", GetLastError());
|
|
return hr;
|
|
}
|
|
|
|
if (bExternalInit)
|
|
{
|
|
hr = IContextMenu_QueryInterface(cmobj, &IID_IShellExtInit, (void**)&shext);
|
|
if (hr != S_OK)
|
|
{
|
|
TRACE("Failed to query for interface IID_IShellExtInit\n");
|
|
IContextMenu_Release(cmobj);
|
|
return FALSE;
|
|
}
|
|
hr = IShellExtInit_Initialize(shext, NULL, This->pDataObj, hKey);
|
|
IShellExtInit_Release(shext);
|
|
if (hr != S_OK)
|
|
{
|
|
TRACE("Failed to initialize shell extension error %x\n", hr);
|
|
IContextMenu_Release(cmobj);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
curEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry));
|
|
if(!curEntry)
|
|
{
|
|
IContextMenu_Release(cmobj);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
curEntry->iIdCmdFirst = 0;
|
|
curEntry->Next = NULL;
|
|
curEntry->NumIds = 0;
|
|
curEntry->CMenu = cmobj;
|
|
memcpy(&curEntry->ClassID, szClass, sizeof(CLSID));
|
|
|
|
if (This->dhead)
|
|
{
|
|
PDynamicShellEntry pEntry = This->dhead;
|
|
|
|
while(pEntry->Next)
|
|
{
|
|
pEntry = pEntry->Next;
|
|
}
|
|
|
|
pEntry->Next = curEntry;
|
|
}
|
|
else
|
|
{
|
|
This->dhead = curEntry;
|
|
}
|
|
|
|
|
|
if (!memcmp(szClass, &CLSID_NewMenu, sizeof(CLSID)))
|
|
{
|
|
/* A REAL UGLY HACK */
|
|
INewItem_SetCurrentShellFolder(This->dcm.psf);
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
static
|
|
UINT
|
|
EnumerateDynamicContextHandlerForKey(IDefaultContextMenuImpl *This, HKEY hRootKey)
|
|
{
|
|
WCHAR szKey[MAX_PATH] = {0};
|
|
WCHAR szName[MAX_PATH] = {0};
|
|
DWORD dwIndex, dwName;
|
|
LONG res;
|
|
HRESULT hResult;
|
|
UINT index;
|
|
CLSID clsid;
|
|
HKEY hKey;
|
|
|
|
static const WCHAR szShellEx[] = { 's','h','e','l','l','e','x','\\','C','o','n','t','e','x','t','M','e','n','u','H','a','n','d','l','e','r','s',0 };
|
|
|
|
if (RegOpenKeyExW(hRootKey, szShellEx, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
|
|
{
|
|
TRACE("RegOpenKeyExW failed for key %s\n", debugstr_w(szKey));
|
|
return 0;
|
|
}
|
|
|
|
dwIndex = 0;
|
|
index = 0;
|
|
do
|
|
{
|
|
dwName = MAX_PATH;
|
|
res = RegEnumKeyExW(hKey, dwIndex, szName, &dwName, NULL, NULL, NULL, NULL);
|
|
if (res == ERROR_SUCCESS)
|
|
{
|
|
hResult = CLSIDFromString(szName, &clsid);
|
|
if (hResult != S_OK)
|
|
{
|
|
dwName = MAX_PATH;
|
|
if (RegGetValueW(hKey, szName, NULL, RRF_RT_REG_SZ, NULL, szKey, &dwName) == ERROR_SUCCESS)
|
|
{
|
|
hResult = CLSIDFromString(szKey, &clsid);
|
|
}
|
|
}
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
if (This->bGroupPolicyActive)
|
|
{
|
|
if (RegGetValueW(HKEY_LOCAL_MACHINE,
|
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
|
|
szKey,
|
|
RRF_RT_REG_SZ,
|
|
NULL,
|
|
NULL,
|
|
&dwName) == ERROR_SUCCESS)
|
|
{
|
|
SH_LoadDynamicContextMenuHandler(This, hKey, &clsid, TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SH_LoadDynamicContextMenuHandler(This, hKey, &clsid, TRUE);
|
|
}
|
|
}
|
|
}
|
|
dwIndex++;
|
|
}while(res == ERROR_SUCCESS);
|
|
|
|
RegCloseKey(hKey);
|
|
return index;
|
|
}
|
|
|
|
|
|
static
|
|
UINT
|
|
InsertMenuItemsOfDynamicContextMenuExtension(IDefaultContextMenuImpl * This, HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast)
|
|
{
|
|
PDynamicShellEntry curEntry;
|
|
HRESULT hResult;
|
|
|
|
if (!This->dhead)
|
|
{
|
|
This->iIdSHEFirst = 0;
|
|
This->iIdSHELast = 0;
|
|
return indexMenu;
|
|
}
|
|
|
|
curEntry = This->dhead;
|
|
idCmdFirst = 0x5000;
|
|
idCmdLast = 0x6000;
|
|
This->iIdSHEFirst = idCmdFirst;
|
|
do
|
|
{
|
|
hResult = IContextMenu_QueryContextMenu(curEntry->CMenu, hMenu, indexMenu++, idCmdFirst, idCmdLast, CMF_NORMAL);
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
curEntry->iIdCmdFirst = idCmdFirst;
|
|
curEntry->NumIds = LOWORD(hResult);
|
|
indexMenu += curEntry->NumIds;
|
|
idCmdFirst += curEntry->NumIds + 0x10;
|
|
}
|
|
TRACE("curEntry %p hresult %x contextmenu %p cmdfirst %x num ids %x\n", curEntry, hResult, curEntry->CMenu, curEntry->iIdCmdFirst, curEntry->NumIds);
|
|
curEntry = curEntry->Next;
|
|
}while(curEntry);
|
|
|
|
This->iIdSHELast = idCmdFirst;
|
|
TRACE("SH_LoadContextMenuHandlers first %x last %x\n", This->iIdSHEFirst, This->iIdSHELast);
|
|
return indexMenu;
|
|
}
|
|
|
|
UINT
|
|
BuildBackgroundContextMenu(
|
|
IDefaultContextMenuImpl * This,
|
|
HMENU hMenu,
|
|
UINT iIdCmdFirst,
|
|
UINT iIdCmdLast,
|
|
UINT uFlags)
|
|
{
|
|
MENUITEMINFOW mii;
|
|
WCHAR szBuffer[MAX_PATH];
|
|
UINT indexMenu = 0;
|
|
HMENU hSubMenu;
|
|
HKEY hKey;
|
|
|
|
ZeroMemory(&mii, sizeof(mii));
|
|
|
|
TRACE("BuildBackgroundContextMenu entered\n");
|
|
|
|
if (!_ILIsDesktop(This->dcm.pidlFolder))
|
|
{
|
|
/* view option is only available in browsing mode */
|
|
hSubMenu = LoadMenuA(shell32_hInstance, "MENU_001");
|
|
if (hSubMenu)
|
|
{
|
|
szBuffer[0] = 0;
|
|
LoadStringW(shell32_hInstance, FCIDM_SHVIEW_VIEW, szBuffer, MAX_PATH);
|
|
szBuffer[MAX_PATH-1] = 0;
|
|
|
|
TRACE("szBuffer %s\n", debugstr_w(szBuffer));
|
|
|
|
mii.cbSize = sizeof(mii);
|
|
mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU | MIIM_ID;
|
|
mii.fType = MFT_STRING;
|
|
mii.wID = iIdCmdFirst++;
|
|
mii.dwTypeData = szBuffer;
|
|
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);
|
|
}
|
|
/* load extensions from HKCR\* key */
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT,
|
|
L"*",
|
|
0,
|
|
KEY_READ,
|
|
&hKey) == ERROR_SUCCESS)
|
|
{
|
|
EnumerateDynamicContextHandlerForKey(This, hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
/* load create new shell extension */
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT,
|
|
L"CLSID\\{D969A300-E7FF-11d0-A93B-00A0C90F2719}",
|
|
0,
|
|
KEY_READ,
|
|
&hKey) == ERROR_SUCCESS)
|
|
{
|
|
SH_LoadDynamicContextMenuHandler(This, hKey, &CLSID_NewMenu, TRUE);
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
if (InsertMenuItemsOfDynamicContextMenuExtension(This, 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;
|
|
}
|
|
|
|
static
|
|
UINT
|
|
AddStaticContextMenusToMenu(
|
|
HMENU hMenu,
|
|
UINT indexMenu,
|
|
IDefaultContextMenuImpl * This)
|
|
{
|
|
MENUITEMINFOW mii;
|
|
UINT idResource;
|
|
PStaticShellEntry curEntry;
|
|
WCHAR szVerb[40];
|
|
WCHAR szTemp[50];
|
|
DWORD dwSize;
|
|
UINT fState;
|
|
UINT Length;
|
|
|
|
mii.cbSize = sizeof(mii);
|
|
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
|
|
mii.fType = MFT_STRING;
|
|
mii.fState = MFS_ENABLED;
|
|
mii.wID = 0x4000;
|
|
This->iIdSCMFirst = mii.wID;
|
|
|
|
curEntry = This->shead;
|
|
|
|
while(curEntry)
|
|
{
|
|
fState = MFS_ENABLED;
|
|
if (!wcsicmp(curEntry->szVerb, L"open"))
|
|
{
|
|
fState |= MFS_DEFAULT;
|
|
idResource = IDS_OPEN_VERB;
|
|
}
|
|
else if (!wcsicmp(curEntry->szVerb, L"runas"))
|
|
idResource = IDS_RUNAS_VERB;
|
|
else if (!wcsicmp(curEntry->szVerb, L"edit"))
|
|
idResource = IDS_EDIT_VERB;
|
|
else if (!wcsicmp(curEntry->szVerb, L"find"))
|
|
idResource = IDS_FIND_VERB;
|
|
else if (!wcsicmp(curEntry->szVerb, L"print"))
|
|
idResource = IDS_PRINT_VERB;
|
|
else if (!wcsicmp(curEntry->szVerb, L"play"))
|
|
idResource = IDS_PLAY_VERB;
|
|
else if (!wcsicmp(curEntry->szVerb, L"preview"))
|
|
idResource = IDS_PREVIEW_VERB;
|
|
else
|
|
idResource = 0;
|
|
|
|
if (idResource > 0)
|
|
{
|
|
if (LoadStringW(shell32_hInstance, idResource, szVerb, sizeof(szVerb)/sizeof(WCHAR)))
|
|
{
|
|
/* use translated verb */
|
|
szVerb[(sizeof(szVerb)/sizeof(WCHAR))-1] = L'\0';
|
|
mii.dwTypeData = szVerb;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Length = wcslen(curEntry->szClass) + wcslen(curEntry->szVerb) + 8;
|
|
if (Length < sizeof(szTemp)/sizeof(WCHAR))
|
|
{
|
|
wcscpy(szTemp, curEntry->szClass);
|
|
wcscat(szTemp, L"\\shell\\");
|
|
wcscat(szTemp, curEntry->szVerb);
|
|
dwSize = sizeof(szVerb);
|
|
|
|
if (RegGetValueW(HKEY_CLASSES_ROOT, szTemp, NULL, RRF_RT_REG_SZ, NULL, szVerb, &dwSize) == ERROR_SUCCESS)
|
|
{
|
|
/* use description for the menu entry */
|
|
mii.dwTypeData = szVerb;
|
|
}
|
|
else
|
|
{
|
|
/* use verb for the menu entry */
|
|
mii.dwTypeData = curEntry->szVerb;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
mii.cch = wcslen(mii.dwTypeData);
|
|
mii.fState = fState;
|
|
InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii);
|
|
|
|
mii.wID++;
|
|
curEntry = curEntry->Next;
|
|
}
|
|
This->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 szText[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), szText, sizeof(szText)/sizeof(WCHAR)))
|
|
{
|
|
szText[(sizeof(szText)/sizeof(WCHAR))-1] = 0;
|
|
mii.dwTypeData = szText;
|
|
}
|
|
else
|
|
{
|
|
TRACE("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
|
|
BuildShellItemContextMenu(
|
|
IDefaultContextMenuImpl * This,
|
|
HMENU hMenu,
|
|
UINT iIdCmdFirst,
|
|
UINT iIdCmdLast,
|
|
UINT uFlags)
|
|
{
|
|
WCHAR szPath[MAX_PATH];
|
|
WCHAR szTemp[40];
|
|
HKEY hKey;
|
|
UINT indexMenu;
|
|
SFGAOF rfg;
|
|
HRESULT hr;
|
|
BOOL bAddSep;
|
|
GUID * guid;
|
|
BOOL bClipboardData;
|
|
STRRET strFile;
|
|
LPWSTR pOffset;
|
|
DWORD dwSize;
|
|
|
|
TRACE("BuildShellItemContextMenu entered\n");
|
|
|
|
if (IShellFolder2_GetDisplayNameOf(This->dcm.psf, This->dcm.apidl[0], SHGDN_FORPARSING, &strFile) == S_OK)
|
|
{
|
|
if (StrRetToBufW(&strFile, This->dcm.apidl[0], szPath, MAX_PATH) == S_OK)
|
|
{
|
|
pOffset = wcsrchr(szPath, L'.');
|
|
if (pOffset)
|
|
{
|
|
/* enumerate dynamic/static for a given file class */
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pOffset, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
/* add static verbs */
|
|
SH_AddStaticEntryForFileClass(This, pOffset);
|
|
/* load dynamic extensions from file extension key */
|
|
EnumerateDynamicContextHandlerForKey(This, hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
dwSize = sizeof(szTemp);
|
|
if (RegGetValueW(HKEY_CLASSES_ROOT, pOffset, NULL, RRF_RT_REG_SZ, NULL, szTemp, &dwSize) == ERROR_SUCCESS)
|
|
{
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szTemp, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
/* add static verbs from progid key */
|
|
SH_AddStaticEntryForFileClass(This, szTemp);
|
|
/* load dynamic extensions from progid key */
|
|
EnumerateDynamicContextHandlerForKey(This, hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
}
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"*", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
/* load default extensions */
|
|
EnumerateDynamicContextHandlerForKey(This, hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
guid = _ILGetGUIDPointer(This->dcm.apidl[0]);
|
|
if (guid)
|
|
{
|
|
LPOLESTR pwszCLSID;
|
|
WCHAR buffer[60];
|
|
|
|
wcscpy(buffer, L"CLSID\\");
|
|
hr = StringFromCLSID(guid, &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(This, hKey);
|
|
SH_AddStaticEntryForFileClass(This, buffer);
|
|
RegCloseKey(hKey);
|
|
}
|
|
CoTaskMemFree(pwszCLSID);
|
|
}
|
|
}
|
|
|
|
|
|
if (_ILIsDrive(This->dcm.apidl[0]))
|
|
{
|
|
SH_AddStaticEntryForFileClass(This, L"Drive");
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Drive", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
EnumerateDynamicContextHandlerForKey(This, hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
}
|
|
|
|
/* add static actions */
|
|
rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
|
|
hr = IShellFolder_GetAttributesOf(This->dcm.psf, This->dcm.cidl, This->dcm.apidl, &rfg);
|
|
if (!SUCCEEDED(hr))
|
|
rfg = 0;
|
|
|
|
if (rfg & SFGAO_FOLDER)
|
|
{
|
|
/* add the default verbs open / explore */
|
|
SH_AddStaticEntryForFileClass(This, L"Folder");
|
|
SH_AddStaticEntryForFileClass(This, L"Directory");
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Folder", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
EnumerateDynamicContextHandlerForKey(This, hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
EnumerateDynamicContextHandlerForKey(This, hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
|
|
if (rfg & SFGAO_FILESYSTEM)
|
|
{
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"AllFilesystemObjects", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
/* sendto service is registered here */
|
|
EnumerateDynamicContextHandlerForKey(This, hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
/* add static context menu handlers */
|
|
indexMenu = AddStaticContextMenusToMenu(hMenu, 0, This);
|
|
/* now process dynamic context menu handlers */
|
|
indexMenu = InsertMenuItemsOfDynamicContextMenuExtension(This, hMenu, indexMenu, iIdCmdFirst, iIdCmdLast);
|
|
TRACE("indexMenu %d\n", indexMenu);
|
|
|
|
if (_ILIsDrive(This->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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
WINAPI
|
|
IDefaultContextMenu_fnQueryContextMenu(
|
|
IContextMenu2 *iface,
|
|
HMENU hmenu,
|
|
UINT indexMenu,
|
|
UINT idCmdFirst,
|
|
UINT idCmdLast,
|
|
UINT uFlags)
|
|
{
|
|
IDefaultContextMenuImpl * This = impl_from_IContextMenu(iface);
|
|
if (This->dcm.cidl)
|
|
{
|
|
idCmdFirst = BuildShellItemContextMenu(This, hmenu, idCmdFirst, idCmdLast, uFlags);
|
|
}
|
|
else
|
|
{
|
|
idCmdFirst = BuildBackgroundContextMenu(This, hmenu, idCmdFirst, idCmdLast, uFlags);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi, BOOL bRefresh)
|
|
{
|
|
LPSHELLBROWSER lpSB;
|
|
LPSHELLVIEW lpSV = NULL;
|
|
HWND hwndSV = NULL;
|
|
|
|
if((lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0)))
|
|
{
|
|
if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))
|
|
{
|
|
IShellView_GetWindow(lpSV, &hwndSV);
|
|
}
|
|
}
|
|
|
|
if (LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_REFRESH || bRefresh)
|
|
{
|
|
if (lpSV)
|
|
IShellView_Refresh(lpSV);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
SendMessageW(hwndSV, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
DoPaste(
|
|
IDefaultContextMenuImpl *This,
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
IDataObject * pda;
|
|
STGMEDIUM medium;
|
|
FORMATETC formatetc;
|
|
LPITEMIDLIST * apidl;
|
|
LPITEMIDLIST pidl;
|
|
IShellFolder *psfFrom = NULL, *psfDesktop, *psfTarget = NULL;
|
|
LPIDA lpcida;
|
|
ISFHelper *psfhlpdst, *psfhlpsrc;
|
|
HRESULT hr;
|
|
|
|
if (OleGetClipboard(&pda) != S_OK)
|
|
return E_FAIL;
|
|
|
|
InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
|
|
hr = IDataObject_GetData(pda,&formatetc,&medium);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
IDataObject_Release(pda);
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* lock the handle */
|
|
lpcida = GlobalLock(medium.u.hGlobal);
|
|
if (!lpcida)
|
|
{
|
|
ReleaseStgMedium(&medium);
|
|
IDataObject_Release(pda);
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* convert the data into pidl */
|
|
apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
|
|
|
|
if (!apidl)
|
|
return E_FAIL;
|
|
|
|
if (FAILED(SHGetDesktopFolder(&psfDesktop)))
|
|
{
|
|
SHFree(pidl);
|
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
ReleaseStgMedium(&medium);
|
|
IDataObject_Release(pda);
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (_ILIsDesktop(pidl))
|
|
{
|
|
/* use desktop shellfolder */
|
|
psfFrom = psfDesktop;
|
|
}
|
|
else if (FAILED(IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (LPVOID*)&psfFrom)))
|
|
{
|
|
ERR("no IShellFolder\n");
|
|
|
|
IShellFolder_Release(psfDesktop);
|
|
SHFree(pidl);
|
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
ReleaseStgMedium(&medium);
|
|
IDataObject_Release(pda);
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (This->dcm.cidl)
|
|
{
|
|
IShellFolder_Release(psfDesktop);
|
|
hr = IShellFolder_BindToObject(This->dcm.psf, This->dcm.apidl[0], NULL, &IID_IShellFolder, (LPVOID*)&psfTarget);
|
|
}
|
|
else
|
|
{
|
|
IPersistFolder2 *ppf2 = NULL;
|
|
LPITEMIDLIST pidl;
|
|
|
|
/* cidl is zero due to explorer view */
|
|
hr = IShellFolder_QueryInterface (This->dcm.psf, &IID_IPersistFolder2, (LPVOID *) &ppf2);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = IPersistFolder2_GetCurFolder (ppf2, &pidl);
|
|
IPersistFolder2_Release(ppf2);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (_ILIsDesktop(pidl))
|
|
{
|
|
/* use desktop shellfolder */
|
|
psfTarget = psfDesktop;
|
|
}
|
|
else
|
|
{
|
|
/* retrieve target desktop folder */
|
|
hr = IShellFolder_BindToObject(psfDesktop, 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");
|
|
|
|
IShellFolder_Release(psfFrom);
|
|
SHFree(pidl);
|
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
ReleaseStgMedium(&medium);
|
|
IDataObject_Release(pda);
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
/* get source and destination shellfolder */
|
|
if (FAILED(IShellFolder_QueryInterface(psfTarget, &IID_ISFHelper, (LPVOID*)&psfhlpdst)))
|
|
{
|
|
ERR("no IID_ISFHelper for destination\n");
|
|
|
|
IShellFolder_Release(psfFrom);
|
|
IShellFolder_Release(psfTarget);
|
|
SHFree(pidl);
|
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
ReleaseStgMedium(&medium);
|
|
IDataObject_Release(pda);
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (FAILED(IShellFolder_QueryInterface(psfFrom, &IID_ISFHelper, (LPVOID*)&psfhlpsrc)))
|
|
{
|
|
ERR("no IID_ISFHelper for source\n");
|
|
|
|
ISFHelper_Release(psfhlpdst);
|
|
IShellFolder_Release(psfFrom);
|
|
IShellFolder_Release(psfTarget);
|
|
SHFree(pidl);
|
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
ReleaseStgMedium(&medium);
|
|
IDataObject_Release(pda);
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* FIXXME
|
|
* do we want to perform a copy or move ???
|
|
*/
|
|
hr = ISFHelper_CopyItems(psfhlpdst, psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl);
|
|
|
|
ISFHelper_Release(psfhlpdst);
|
|
ISFHelper_Release(psfhlpsrc);
|
|
IShellFolder_Release(psfFrom);
|
|
IShellFolder_Release(psfTarget);
|
|
SHFree(pidl);
|
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
ReleaseStgMedium(&medium);
|
|
IDataObject_Release(pda);
|
|
TRACE("CP result %x\n",hr);
|
|
return S_OK;
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
DoOpenOrExplore(
|
|
IDefaultContextMenuImpl *iface,
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
BOOL
|
|
GetUniqueFileName(LPWSTR szBasePath, LPWSTR szExt, LPWSTR szTarget, BOOL bShortcut)
|
|
{
|
|
UINT RetryCount = 0, Length;
|
|
WCHAR szLnk[40];
|
|
HANDLE hFile;
|
|
|
|
if (!bShortcut)
|
|
{
|
|
Length = LoadStringW(shell32_hInstance, IDS_LNK_FILE, szLnk, sizeof(szLnk)/sizeof(WCHAR));
|
|
}
|
|
|
|
do
|
|
{
|
|
if (!bShortcut)
|
|
{
|
|
if (RetryCount)
|
|
swprintf(szTarget, L"%s%s(%u).%s", szLnk, szBasePath, RetryCount, szExt);
|
|
else
|
|
swprintf(szTarget, L"%s%s.%s", szLnk, szBasePath, szExt);
|
|
}
|
|
else
|
|
{
|
|
if (RetryCount)
|
|
swprintf(szTarget, L"%s(%u).%s", szBasePath, RetryCount, szExt);
|
|
else
|
|
swprintf(szTarget, L"%s.%s", szBasePath, szExt);
|
|
}
|
|
|
|
hFile = CreateFileW(szTarget, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(hFile);
|
|
return TRUE;
|
|
}
|
|
|
|
}while(RetryCount++ < 100);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
DoCreateLink(
|
|
IDefaultContextMenuImpl *This,
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
WCHAR szPath[MAX_PATH];
|
|
WCHAR szTarget[MAX_PATH] = {0};
|
|
WCHAR szDirPath[MAX_PATH];
|
|
LPWSTR pszFile;
|
|
STRRET strFile;
|
|
LPWSTR pszExt;
|
|
HRESULT hr;
|
|
IShellLinkW * nLink;
|
|
IPersistFile * ipf;
|
|
static WCHAR szLnk[] = L"lnk";
|
|
|
|
if (IShellFolder2_GetDisplayNameOf(This->dcm.psf, This->dcm.apidl[0], SHGDN_FORPARSING, &strFile) != S_OK)
|
|
{
|
|
ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (StrRetToBufW(&strFile, This->dcm.apidl[0], szPath, MAX_PATH) != S_OK)
|
|
return E_FAIL;
|
|
|
|
pszExt = wcsrchr(szPath, L'.');
|
|
|
|
if (pszExt && !wcsicmp(pszExt + 1, szLnk))
|
|
{
|
|
if (!GetUniqueFileName(szPath, pszExt + 1, szTarget, TRUE))
|
|
return E_FAIL;
|
|
|
|
hr = IShellLink_ConstructFromFile(NULL, &IID_IPersistFile, This->dcm.apidl[0], (LPVOID*)&ipf);
|
|
if (hr != S_OK)
|
|
{
|
|
return hr;
|
|
}
|
|
hr = IPersistFile_Save(ipf, szTarget, FALSE);
|
|
IPersistFile_Release(ipf);
|
|
NotifyShellViewWindow(lpcmi, TRUE);
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
if (!GetUniqueFileName(szPath, szLnk, szTarget, TRUE))
|
|
return E_FAIL;
|
|
|
|
hr = IShellLink_Constructor(NULL, &IID_IShellLinkW, (LPVOID*)&nLink);
|
|
if (hr != S_OK)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
GetFullPathName(szPath, MAX_PATH, szDirPath, &pszFile);
|
|
if (pszFile) pszFile[0] = 0;
|
|
|
|
if (SUCCEEDED(IShellLinkW_SetPath(nLink, szPath)) &&
|
|
SUCCEEDED(IShellLinkW_SetWorkingDirectory(nLink, szDirPath)))
|
|
{
|
|
if (SUCCEEDED(IShellLinkW_QueryInterface(nLink, &IID_IPersistFile, (LPVOID*)&ipf)))
|
|
{
|
|
hr = IPersistFile_Save(ipf, szTarget, TRUE);
|
|
IPersistFile_Release(ipf);
|
|
}
|
|
}
|
|
IShellLinkW_Release(nLink);
|
|
NotifyShellViewWindow(lpcmi, TRUE);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
DoDelete(
|
|
IDefaultContextMenuImpl *This,
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
HRESULT hr;
|
|
STRRET strTemp;
|
|
WCHAR szPath[MAX_PATH];
|
|
LPWSTR wszPath, wszPos;
|
|
SHFILEOPSTRUCTW op;
|
|
int ret;
|
|
LPSHELLBROWSER lpSB;
|
|
HWND hwnd;
|
|
|
|
hr = IShellFolder2_GetDisplayNameOf(This->dcm.psf, This->dcm.apidl[0], SHGDN_FORPARSING, &strTemp);
|
|
if(hr != S_OK)
|
|
{
|
|
ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr);
|
|
return hr;
|
|
}
|
|
ZeroMemory(szPath, sizeof(szPath));
|
|
hr = StrRetToBufW(&strTemp, This->dcm.apidl[0], szPath, MAX_PATH);
|
|
if (hr != S_OK)
|
|
{
|
|
ERR("StrRetToBufW failed with %x\n", hr);
|
|
return hr;
|
|
}
|
|
|
|
/* Only keep the base path */
|
|
wszPos = strrchrW(szPath, '\\');
|
|
if (wszPos != NULL)
|
|
{
|
|
*(wszPos + 1) = '\0';
|
|
}
|
|
|
|
wszPath = build_paths_list(szPath, This->dcm.cidl, This->dcm.apidl);
|
|
|
|
ZeroMemory(&op, sizeof(op));
|
|
op.hwnd = GetActiveWindow();
|
|
op.wFunc = FO_DELETE;
|
|
op.pFrom = wszPath;
|
|
op.fFlags = FOF_ALLOWUNDO;
|
|
ret = SHFileOperationW(&op);
|
|
|
|
if (ret)
|
|
{
|
|
ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(wszPath));
|
|
return S_OK;
|
|
}
|
|
|
|
/* get the active IShellView */
|
|
if ((lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0)))
|
|
{
|
|
/* is the treeview focused */
|
|
if (SUCCEEDED(IShellBrowser_GetControlWindow(lpSB, FCW_TREE, &hwnd)))
|
|
{
|
|
HTREEITEM hItem = TreeView_GetSelection(hwnd);
|
|
if (hItem)
|
|
{
|
|
(void)TreeView_DeleteItem(hwnd, hItem);
|
|
}
|
|
}
|
|
}
|
|
NotifyShellViewWindow(lpcmi, TRUE);
|
|
|
|
HeapFree(GetProcessHeap(), 0, wszPath);
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
DoCopyOrCut(
|
|
IDefaultContextMenuImpl *iface,
|
|
LPCMINVOKECOMMANDINFO lpcmi,
|
|
BOOL bCopy)
|
|
{
|
|
LPSHELLBROWSER lpSB;
|
|
LPSHELLVIEW lpSV;
|
|
LPDATAOBJECT pDataObj;
|
|
HRESULT hr;
|
|
|
|
if (SUCCEEDED(SHCreateDataObject(iface->dcm.pidlFolder, iface->dcm.cidl, iface->dcm.apidl, NULL, &IID_IDataObject, (void**)&pDataObj)))
|
|
{
|
|
hr = OleSetClipboard(pDataObj);
|
|
IDataObject_Release(pDataObj);
|
|
return hr;
|
|
}
|
|
|
|
lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0);
|
|
if (!lpSB)
|
|
{
|
|
TRACE("failed to get shellbrowser\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
hr = IShellBrowser_QueryActiveShellView(lpSB, &lpSV);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE("failed to query the active shellview\n");
|
|
return hr;
|
|
}
|
|
|
|
hr = IShellView_GetItemObject(lpSV, SVGIO_SELECTION, &IID_IDataObject, (LPVOID*)&pDataObj);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE("failed to get item object\n");
|
|
return hr;
|
|
}
|
|
|
|
hr = OleSetClipboard(pDataObj);
|
|
if (FAILED(hr))
|
|
{
|
|
WARN("OleSetClipboard failed");
|
|
}
|
|
IDataObject_Release(pDataObj);
|
|
IShellView_Release(lpSV);
|
|
return S_OK;
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
DoRename(
|
|
IDefaultContextMenuImpl *This,
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
LPSHELLBROWSER lpSB;
|
|
LPSHELLVIEW lpSV;
|
|
HWND hwnd;
|
|
|
|
/* get the active IShellView */
|
|
if ((lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0)))
|
|
{
|
|
/* is the treeview focused */
|
|
if (SUCCEEDED(IShellBrowser_GetControlWindow(lpSB, FCW_TREE, &hwnd)))
|
|
{
|
|
HTREEITEM hItem = TreeView_GetSelection(hwnd);
|
|
if (hItem)
|
|
{
|
|
(void)TreeView_EditLabel(hwnd, hItem);
|
|
}
|
|
}
|
|
|
|
if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))
|
|
{
|
|
IShellView_SelectItem(lpSV, This->dcm.apidl[0],
|
|
SVSI_DESELECTOTHERS|SVSI_EDIT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_SELECT);
|
|
IShellView_Release(lpSV);
|
|
return S_OK;
|
|
}
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
DoProperties(
|
|
IDefaultContextMenuImpl *This,
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
WCHAR szDrive[MAX_PATH];
|
|
STRRET strFile;
|
|
|
|
if (This->dcm.cidl &&_ILIsMyComputer(This->dcm.apidl[0]))
|
|
{
|
|
ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL, NULL, SW_SHOWNORMAL);
|
|
return S_OK;
|
|
}
|
|
else if (This->dcm.cidl == 0 && _ILIsDesktop(This->dcm.pidlFolder))
|
|
{
|
|
ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL);
|
|
return S_OK;
|
|
}
|
|
else if (_ILIsDrive(This->dcm.apidl[0]))
|
|
{
|
|
ILGetDisplayName(This->dcm.apidl[0], szDrive);
|
|
SH_ShowDriveProperties(szDrive, This->dcm.pidlFolder, This->dcm.apidl);
|
|
return S_OK;
|
|
}
|
|
else if (_ILIsNetHood(This->dcm.apidl[0]))
|
|
{
|
|
//FIXME path!
|
|
ShellExecuteW(NULL, L"open", L"explorer.exe",
|
|
L"/n,::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
|
|
NULL, SW_SHOWDEFAULT);
|
|
return S_OK;
|
|
}
|
|
else if (_ILIsBitBucket(This->dcm.apidl[0]))
|
|
{
|
|
/* FIXME
|
|
* detect the drive path of bitbucket if appropiate
|
|
*/
|
|
|
|
SH_ShowRecycleBinProperties(L'C');
|
|
return S_OK;
|
|
}
|
|
|
|
if (This->dcm.cidl > 1)
|
|
WARN("SHMultiFileProperties is not yet implemented\n");
|
|
|
|
if (IShellFolder2_GetDisplayNameOf(This->dcm.psf, This->dcm.apidl[0], SHGDN_FORPARSING, &strFile) != S_OK)
|
|
{
|
|
ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (StrRetToBufW(&strFile, This->dcm.apidl[0], szDrive, MAX_PATH) != S_OK)
|
|
return E_FAIL;
|
|
|
|
return SH_ShowPropertiesDialog(szDrive, This->dcm.pidlFolder, This->dcm.apidl);
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
DoFormat(
|
|
IDefaultContextMenuImpl *This,
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
char sDrive[5] = {0};
|
|
|
|
if (!_ILGetDrive(This->dcm.apidl[0], sDrive, sizeof(sDrive)))
|
|
{
|
|
ERR("pidl is not a drive\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
SHFormatDrive(lpcmi->hwnd, sDrive[0] - 'A', SHFMT_ID_DEFAULT, 0);
|
|
return S_OK;
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
DoDynamicShellExtensions(
|
|
IDefaultContextMenuImpl *This,
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
UINT verb = LOWORD(lpcmi->lpVerb);
|
|
PDynamicShellEntry pCurrent = This->dhead;
|
|
|
|
TRACE("verb %p first %x last %x", lpcmi->lpVerb, This->iIdSHEFirst, This->iIdSHELast);
|
|
|
|
while(pCurrent && verb > pCurrent->iIdCmdFirst + pCurrent->NumIds)
|
|
pCurrent = pCurrent->Next;
|
|
|
|
if (!pCurrent)
|
|
return E_FAIL;
|
|
|
|
if (verb >= pCurrent->iIdCmdFirst && verb <= pCurrent->iIdCmdFirst + pCurrent->NumIds)
|
|
{
|
|
/* invoke the dynamic context menu */
|
|
lpcmi->lpVerb = MAKEINTRESOURCEA(verb - pCurrent->iIdCmdFirst);
|
|
return IContextMenu_InvokeCommand(pCurrent->CMenu, lpcmi);
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
static
|
|
HRESULT
|
|
DoStaticShellExtensions(
|
|
IDefaultContextMenuImpl *This,
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
STRRET strFile;
|
|
WCHAR szPath[MAX_PATH];
|
|
WCHAR szDir[MAX_PATH];
|
|
SHELLEXECUTEINFOW sei;
|
|
PStaticShellEntry pCurrent = This->shead;
|
|
int verb = LOWORD(lpcmi->lpVerb) - This->iIdSCMFirst;
|
|
|
|
|
|
while(pCurrent && verb-- > 0)
|
|
pCurrent = pCurrent->Next;
|
|
|
|
if (verb > 0)
|
|
return E_FAIL;
|
|
|
|
|
|
if (IShellFolder2_GetDisplayNameOf(This->dcm.psf, This->dcm.apidl[0], SHGDN_FORPARSING, &strFile) != S_OK)
|
|
{
|
|
ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (StrRetToBufW(&strFile, This->dcm.apidl[0], szPath, MAX_PATH) != S_OK)
|
|
return E_FAIL;
|
|
|
|
wcscpy(szDir, szPath);
|
|
PathRemoveFileSpec(szDir);
|
|
|
|
ZeroMemory(&sei, sizeof(sei));
|
|
sei.cbSize = sizeof(sei);
|
|
sei.fMask = SEE_MASK_CLASSNAME;
|
|
sei.lpClass = pCurrent->szClass;
|
|
sei.hwnd = lpcmi->hwnd;
|
|
sei.nShow = SW_SHOWNORMAL;
|
|
sei.lpVerb = pCurrent->szVerb;
|
|
sei.lpFile = szPath;
|
|
sei.lpDirectory = szDir;
|
|
ShellExecuteExW(&sei);
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
WINAPI
|
|
IDefaultContextMenu_fnInvokeCommand(
|
|
IContextMenu2 *iface,
|
|
LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
IDefaultContextMenuImpl * This = impl_from_IContextMenu(iface);
|
|
|
|
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(This, lpcmi);
|
|
case FCIDM_SHVIEW_OPEN:
|
|
case FCIDM_SHVIEW_EXPLORE:
|
|
return DoOpenOrExplore(This, lpcmi);
|
|
case FCIDM_SHVIEW_COPY:
|
|
case FCIDM_SHVIEW_CUT:
|
|
return DoCopyOrCut(This, lpcmi, LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_COPY);
|
|
case FCIDM_SHVIEW_CREATELINK:
|
|
return DoCreateLink(This, lpcmi);
|
|
case FCIDM_SHVIEW_DELETE:
|
|
return DoDelete(This, lpcmi);
|
|
case FCIDM_SHVIEW_RENAME:
|
|
return DoRename(This, lpcmi);
|
|
case FCIDM_SHVIEW_PROPERTIES:
|
|
return DoProperties(This, lpcmi);
|
|
case 0x7ABC:
|
|
return DoFormat(This, lpcmi);
|
|
}
|
|
|
|
if (This->iIdSHEFirst && This->iIdSHELast)
|
|
{
|
|
if (LOWORD(lpcmi->lpVerb) >= This->iIdSHEFirst && LOWORD(lpcmi->lpVerb) <= This->iIdSHELast)
|
|
{
|
|
return DoDynamicShellExtensions(This, lpcmi);
|
|
}
|
|
}
|
|
|
|
if (This->iIdSCMFirst && This->iIdSCMLast)
|
|
{
|
|
if (LOWORD(lpcmi->lpVerb) >= This->iIdSCMFirst && LOWORD(lpcmi->lpVerb) <= This->iIdSCMLast)
|
|
{
|
|
return DoStaticShellExtensions(This, lpcmi);
|
|
}
|
|
}
|
|
|
|
FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
WINAPI
|
|
IDefaultContextMenu_fnGetCommandString(
|
|
IContextMenu2 *iface,
|
|
UINT_PTR idCommand,
|
|
UINT uFlags,
|
|
UINT* lpReserved,
|
|
LPSTR lpszName,
|
|
UINT uMaxNameLen)
|
|
{
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static
|
|
HRESULT
|
|
WINAPI
|
|
IDefaultContextMenu_fnHandleMenuMsg(
|
|
IContextMenu2 *iface,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const IContextMenu2Vtbl cmvt =
|
|
{
|
|
IDefaultContextMenu_fnQueryInterface,
|
|
IDefaultContextMenu_fnAddRef,
|
|
IDefaultContextMenu_fnRelease,
|
|
IDefaultContextMenu_fnQueryContextMenu,
|
|
IDefaultContextMenu_fnInvokeCommand,
|
|
IDefaultContextMenu_fnGetCommandString,
|
|
IDefaultContextMenu_fnHandleMenuMsg
|
|
};
|
|
static
|
|
HRESULT
|
|
IDefaultContextMenu_Constructor(
|
|
const DEFCONTEXTMENU *pdcm,
|
|
REFIID riid,
|
|
void **ppv)
|
|
{
|
|
IDefaultContextMenuImpl * This;
|
|
HRESULT hr = E_FAIL;
|
|
IDataObject * pDataObj;
|
|
|
|
This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDefaultContextMenuImpl));
|
|
if (This)
|
|
{
|
|
This->lpVtbl = &cmvt;
|
|
This->ref = 1;
|
|
TRACE("cidl %u\n", This->dcm.cidl);
|
|
if (SUCCEEDED(SHCreateDataObject(pdcm->pidlFolder, pdcm->cidl, pdcm->apidl, NULL, &IID_IDataObject, (void**)&pDataObj)))
|
|
{
|
|
This->pDataObj = pDataObj;
|
|
}
|
|
CopyMemory(&This->dcm, pdcm, sizeof(DEFCONTEXTMENU));
|
|
hr = IDefaultContextMenu_fnQueryInterface((IContextMenu2*)This, riid, ppv);
|
|
if (SUCCEEDED(hr))
|
|
IContextMenu_Release((IContextMenu2*)This);
|
|
}
|
|
|
|
TRACE("This(%p)(%x) cidl %u\n",This, hr, This->dcm.cidl);
|
|
return hr;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* SHCreateDefaultContextMenu [SHELL32.325] Vista API
|
|
*
|
|
*/
|
|
|
|
HRESULT
|
|
WINAPI
|
|
SHCreateDefaultContextMenu(
|
|
const DEFCONTEXTMENU *pdcm,
|
|
REFIID riid,
|
|
void **ppv)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
*ppv = NULL;
|
|
hr = IDefaultContextMenu_Constructor( pdcm, riid, ppv );
|
|
|
|
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;
|
|
HRESULT hr;
|
|
|
|
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;
|
|
|
|
hr = SHCreateDefaultContextMenu(&pdcm, &IID_IContextMenu, (void**)ppcm);
|
|
return hr;
|
|
}
|
|
|