reactos/dll/win32/shell32/shv_def_cmenu.c
Amine Khaldi c424146e2c Create a branch for cmake bringup.
svn path=/branches/cmake-bringup/; revision=48236
2010-07-24 18:52:44 +00:00

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;
}