add property page winapi (not finished, I will implement it)
[reactos.git] / reactos / lib / shell32 / shv_item_cmenu.c
index 6db0b03..c517691 100644 (file)
-/*\r
- *     IContextMenu for items in the shellview\r
- *\r
- * Copyright 1998, 2000 Juergen Schmied <juergen.schmied@debitel.net>\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
- */\r
-\r
-#include <string.h>\r
-\r
-#define COBJMACROS\r
-#define NONAMELESSUNION\r
-#define NONAMELESSSTRUCT\r
-\r
-#include "winerror.h"\r
-#include "wine/debug.h"\r
-\r
-#include "windef.h"\r
-#include "wingdi.h"\r
-#include "pidl.h"\r
-#include "shlguid.h"\r
-#include "undocshell.h"\r
-#include "shlobj.h"\r
-\r
-#include "shell32_main.h"\r
-#include "shellfolder.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(shell);\r
-\r
-/**************************************************************************\r
-*  IContextMenu Implementation\r
-*/\r
-typedef struct\r
-{      IContextMenu2Vtbl *lpVtbl;\r
-       DWORD           ref;\r
-       IShellFolder*   pSFParent;\r
-       LPITEMIDLIST    pidl;           /* root pidl */\r
-       LPITEMIDLIST    *apidl;         /* array of child pidls */\r
-       UINT            cidl;\r
-       BOOL            bAllValues;\r
-} ItemCmImpl;\r
-\r
-\r
-static struct IContextMenu2Vtbl cmvt;\r
-\r
-/**************************************************************************\r
-* ISvItemCm_CanRenameItems()\r
-*/\r
-static BOOL ISvItemCm_CanRenameItems(ItemCmImpl *This)\r
-{      UINT  i;\r
-       DWORD dwAttributes;\r
-\r
-       TRACE("(%p)->()\n",This);\r
-\r
-       if(This->apidl)\r
-       {\r
-         for(i = 0; i < This->cidl; i++){}\r
-         if(i > 1) return FALSE;               /* can't rename more than one item at a time*/\r
-         dwAttributes = SFGAO_CANRENAME;\r
-         IShellFolder_GetAttributesOf(This->pSFParent, 1, (LPCITEMIDLIST*)This->apidl, &dwAttributes);\r
-         return dwAttributes & SFGAO_CANRENAME;\r
-       }\r
-       return FALSE;\r
-}\r
-\r
-/**************************************************************************\r
-*   ISvItemCm_Constructor()\r
-*/\r
-IContextMenu2 *ISvItemCm_Constructor(LPSHELLFOLDER pSFParent, LPCITEMIDLIST pidl, LPCITEMIDLIST *apidl, UINT cidl)\r
-{      ItemCmImpl* cm;\r
-       UINT  u;\r
-\r
-       cm = (ItemCmImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ItemCmImpl));\r
-       cm->lpVtbl = &cmvt;\r
-       cm->ref = 1;\r
-       cm->pidl = ILClone(pidl);\r
-       cm->pSFParent = pSFParent;\r
-\r
-       if(pSFParent) IShellFolder_AddRef(pSFParent);\r
-\r
-       cm->apidl = _ILCopyaPidl(apidl, cidl);\r
-       cm->cidl = cidl;\r
-\r
-       cm->bAllValues = 1;\r
-       for(u = 0; u < cidl; u++)\r
-       {\r
-         cm->bAllValues &= (_ILIsValue(apidl[u]) ? 1 : 0);\r
-       }\r
-\r
-       TRACE("(%p)->()\n",cm);\r
-\r
-       return (IContextMenu2*)cm;\r
-}\r
-\r
-/**************************************************************************\r
-*  ISvItemCm_fnQueryInterface\r
-*/\r
-static HRESULT WINAPI ISvItemCm_fnQueryInterface(IContextMenu2 *iface, REFIID riid, LPVOID *ppvObj)\r
-{\r
-       ItemCmImpl *This = (ItemCmImpl *)iface;\r
-\r
-       TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);\r
-\r
-       *ppvObj = NULL;\r
-\r
-        if(IsEqualIID(riid, &IID_IUnknown) ||\r
-           IsEqualIID(riid, &IID_IContextMenu) ||\r
-           IsEqualIID(riid, &IID_IContextMenu2))\r
-       {\r
-         *ppvObj = This;\r
-       }\r
-       else if(IsEqualIID(riid, &IID_IShellExtInit))  /*IShellExtInit*/\r
-       {\r
-         FIXME("-- LPSHELLEXTINIT pointer requested\n");\r
-       }\r
-\r
-       if(*ppvObj)\r
-       {\r
-         IUnknown_AddRef((IUnknown*)*ppvObj);\r
-         TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);\r
-         return S_OK;\r
-       }\r
-       TRACE("-- Interface: E_NOINTERFACE\n");\r
-       return E_NOINTERFACE;\r
-}\r
-\r
-/**************************************************************************\r
-*  ISvItemCm_fnAddRef\r
-*/\r
-static ULONG WINAPI ISvItemCm_fnAddRef(IContextMenu2 *iface)\r
-{\r
-       ItemCmImpl *This = (ItemCmImpl *)iface;\r
-\r
-       TRACE("(%p)->(count=%lu)\n",This, This->ref);\r
-\r
-       return ++(This->ref);\r
-}\r
-\r
-/**************************************************************************\r
-*  ISvItemCm_fnRelease\r
-*/\r
-static ULONG WINAPI ISvItemCm_fnRelease(IContextMenu2 *iface)\r
-{\r
-       ItemCmImpl *This = (ItemCmImpl *)iface;\r
-\r
-       TRACE("(%p)->()\n",This);\r
-\r
-       if (!--(This->ref))\r
-       {\r
-         TRACE(" destroying IContextMenu(%p)\n",This);\r
-\r
-         if(This->pSFParent)\r
-           IShellFolder_Release(This->pSFParent);\r
-\r
-         if(This->pidl)\r
-           SHFree(This->pidl);\r
-\r
-         /*make sure the pidl is freed*/\r
-         _ILFreeaPidl(This->apidl, This->cidl);\r
-\r
-         HeapFree(GetProcessHeap(),0,This);\r
-         return 0;\r
-       }\r
-       return This->ref;\r
-}\r
-\r
-/**************************************************************************\r
-*  ICM_InsertItem()\r
-*/\r
-void WINAPI _InsertMenuItem (\r
-       HMENU hmenu,\r
-       UINT indexMenu,\r
-       BOOL fByPosition,\r
-       UINT wID,\r
-       UINT fType,\r
-       LPSTR dwTypeData,\r
-       UINT fState)\r
-{\r
-       MENUITEMINFOA   mii;\r
-\r
-       ZeroMemory(&mii, sizeof(mii));\r
-       mii.cbSize = sizeof(mii);\r
-       if (fType == MFT_SEPARATOR)\r
-       {\r
-         mii.fMask = MIIM_ID | MIIM_TYPE;\r
-       }\r
-       else\r
-       {\r
-         mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;\r
-         mii.dwTypeData = dwTypeData;\r
-         mii.fState = fState;\r
-       }\r
-       mii.wID = wID;\r
-       mii.fType = fType;\r
-       InsertMenuItemA( hmenu, indexMenu, fByPosition, &mii);\r
-}\r
-\r
-/**************************************************************************\r
-* ISvItemCm_fnQueryContextMenu()\r
-* FIXME: load menu MENU_SHV_FILE out of resources instead if creating\r
-*               each menu item by calling _InsertMenuItem()\r
-*/\r
-static HRESULT WINAPI ISvItemCm_fnQueryContextMenu(\r
-       IContextMenu2 *iface,\r
-       HMENU hmenu,\r
-       UINT indexMenu,\r
-       UINT idCmdFirst,\r
-       UINT idCmdLast,\r
-       UINT uFlags)\r
-{\r
-       ItemCmImpl *This = (ItemCmImpl *)iface;\r
-\r
-       TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",This, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);\r
-\r
-       if (idCmdFirst != 0)\r
-         FIXME("We should use idCmdFirst=%d and idCmdLast=%d for command ids\n", idCmdFirst, idCmdLast);\r
-\r
-       if(!(CMF_DEFAULTONLY & uFlags) && This->cidl>0)\r
-       {\r
-         if(!(uFlags & CMF_EXPLORE))\r
-           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_OPEN, MFT_STRING, "&Select", MFS_ENABLED);\r
-\r
-         if(This->bAllValues)\r
-         {\r
-           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_OPEN, MFT_STRING, "&Open", MFS_ENABLED);\r
-           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_EXPLORE, MFT_STRING, "&Explore", MFS_ENABLED);\r
-         }\r
-         else\r
-         {\r
-           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_EXPLORE, MFT_STRING, "&Explore", MFS_ENABLED);\r
-           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_OPEN, MFT_STRING, "&Open", MFS_ENABLED);\r
-         }\r
-\r
-         SetMenuDefaultItem(hmenu, 0, MF_BYPOSITION);\r
-\r
-         _InsertMenuItem(hmenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);\r
-         _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_COPY, MFT_STRING, "&Copy", MFS_ENABLED);\r
-         _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_CUT, MFT_STRING, "&Cut", MFS_ENABLED);\r
-\r
-         _InsertMenuItem(hmenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);\r
-         _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_DELETE, MFT_STRING, "&Delete", MFS_ENABLED);\r
-\r
-         if(uFlags & CMF_CANRENAME)\r
-           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_RENAME, MFT_STRING, "&Rename", ISvItemCm_CanRenameItems(This) ? MFS_ENABLED : MFS_DISABLED);\r
-\r
-         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (FCIDM_SHVIEWLAST));\r
-       }\r
-       return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);\r
-}\r
-\r
-/**************************************************************************\r
-* DoOpenExplore\r
-*\r
-*  for folders only\r
-*/\r
-\r
-static void DoOpenExplore(\r
-       IContextMenu2 *iface,\r
-       HWND hwnd,\r
-       LPCSTR verb)\r
-{\r
-       ItemCmImpl *This = (ItemCmImpl *)iface;\r
-\r
-       UINT i, bFolderFound = FALSE;\r
-       LPITEMIDLIST    pidlFQ;\r
-       SHELLEXECUTEINFOA       sei;\r
-\r
-       /* Find the first item in the list that is not a value. These commands\r
-           should never be invoked if there isn't at least one folder item in the list.*/\r
-\r
-       for(i = 0; i<This->cidl; i++)\r
-       {\r
-         if(!_ILIsValue(This->apidl[i]))\r
-         {\r
-           bFolderFound = TRUE;\r
-           break;\r
-         }\r
-       }\r
-\r
-       if (!bFolderFound) return;\r
-\r
-       pidlFQ = ILCombine(This->pidl, This->apidl[i]);\r
-\r
-       ZeroMemory(&sei, sizeof(sei));\r
-       sei.cbSize = sizeof(sei);\r
-       sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME;\r
-       sei.lpIDList = pidlFQ;\r
-       sei.lpClass = "Folder";\r
-       sei.hwnd = hwnd;\r
-       sei.nShow = SW_SHOWNORMAL;\r
-       sei.lpVerb = verb;\r
-       ShellExecuteExA(&sei);\r
-       SHFree(pidlFQ);\r
-}\r
-\r
-/**************************************************************************\r
-* DoRename\r
-*/\r
-static void DoRename(\r
-       IContextMenu2 *iface,\r
-       HWND hwnd)\r
-{\r
-       ItemCmImpl *This = (ItemCmImpl *)iface;\r
-\r
-       LPSHELLBROWSER  lpSB;\r
-       LPSHELLVIEW     lpSV;\r
-\r
-       TRACE("(%p)->(wnd=%p)\n",This, hwnd);\r
-\r
-       /* get the active IShellView */\r
-       if ((lpSB = (LPSHELLBROWSER)SendMessageA(hwnd, CWM_GETISHELLBROWSER,0,0)))\r
-       {\r
-         if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))\r
-         {\r
-           TRACE("(sv=%p)\n",lpSV);\r
-           IShellView_SelectItem(lpSV, This->apidl[0],\r
-              SVSI_DESELECTOTHERS|SVSI_EDIT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_SELECT);\r
-           IShellView_Release(lpSV);\r
-         }\r
-       }\r
-}\r
-\r
-/**************************************************************************\r
- * DoDelete\r
- *\r
- * deletes the currently selected items\r
- */\r
-static void DoDelete(IContextMenu2 *iface)\r
-{\r
-       ItemCmImpl *This = (ItemCmImpl *)iface;\r
-       ISFHelper * psfhlp;\r
-\r
-       IShellFolder_QueryInterface(This->pSFParent, &IID_ISFHelper, (LPVOID*)&psfhlp);\r
-       if (psfhlp)\r
-       {\r
-         ISFHelper_DeleteItems(psfhlp, This->cidl, (LPCITEMIDLIST *)This->apidl);\r
-         ISFHelper_Release(psfhlp);\r
-       }\r
-}\r
-\r
-/**************************************************************************\r
- * DoCopyOrCut\r
- *\r
- * copies the currently selected items into the clipboard\r
- */\r
-static BOOL DoCopyOrCut(\r
-       IContextMenu2 *iface,\r
-       HWND hwnd,\r
-       BOOL bCut)\r
-{\r
-       ItemCmImpl *This = (ItemCmImpl *)iface;\r
-\r
-       LPSHELLBROWSER  lpSB;\r
-       LPSHELLVIEW     lpSV;\r
-       LPDATAOBJECT    lpDo;\r
-\r
-       TRACE("(%p)->(wnd=%p,bCut=0x%08x)\n",This, hwnd, bCut);\r
-\r
-       /* get the active IShellView */\r
-       if ((lpSB = (LPSHELLBROWSER)SendMessageA(hwnd, CWM_GETISHELLBROWSER,0,0)))\r
-       {\r
-         if (SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))\r
-         {\r
-           if (SUCCEEDED(IShellView_GetItemObject(lpSV, SVGIO_SELECTION, &IID_IDataObject, (LPVOID*)&lpDo)))\r
-           {\r
-             OleSetClipboard(lpDo);\r
-             IDataObject_Release(lpDo);\r
-           }\r
-           IShellView_Release(lpSV);\r
-         }\r
-       }\r
-       return TRUE;\r
-}\r
-/**************************************************************************\r
-* ISvItemCm_fnInvokeCommand()\r
-*/\r
-static HRESULT WINAPI ISvItemCm_fnInvokeCommand(\r
-       IContextMenu2 *iface,\r
-       LPCMINVOKECOMMANDINFO lpcmi)\r
-{\r
-    ItemCmImpl *This = (ItemCmImpl *)iface;\r
-\r
-    if (lpcmi->cbSize != sizeof(CMINVOKECOMMANDINFO))\r
-        FIXME("Is an EX structure\n");\r
-\r
-    TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);\r
-\r
-    if( HIWORD(lpcmi->lpVerb)==0 && LOWORD(lpcmi->lpVerb) > FCIDM_SHVIEWLAST)\r
-    {\r
-        TRACE("Invalid Verb %x\n",LOWORD(lpcmi->lpVerb));\r
-        return E_INVALIDARG;\r
-    }\r
-\r
-    if (HIWORD(lpcmi->lpVerb) == 0)\r
-    {\r
-        switch(LOWORD(lpcmi->lpVerb))\r
-        {\r
-        case FCIDM_SHVIEW_EXPLORE:\r
-            TRACE("Verb FCIDM_SHVIEW_EXPLORE\n");\r
-            DoOpenExplore(iface, lpcmi->hwnd, "explore");\r
-            break;\r
-        case FCIDM_SHVIEW_OPEN:\r
-            TRACE("Verb FCIDM_SHVIEW_OPEN\n");\r
-            DoOpenExplore(iface, lpcmi->hwnd, "open");\r
-            break;\r
-        case FCIDM_SHVIEW_RENAME:\r
-            TRACE("Verb FCIDM_SHVIEW_RENAME\n");\r
-            DoRename(iface, lpcmi->hwnd);\r
-            break;\r
-        case FCIDM_SHVIEW_DELETE:\r
-            TRACE("Verb FCIDM_SHVIEW_DELETE\n");\r
-            DoDelete(iface);\r
-            break;\r
-        case FCIDM_SHVIEW_COPY:\r
-            TRACE("Verb FCIDM_SHVIEW_COPY\n");\r
-            DoCopyOrCut(iface, lpcmi->hwnd, FALSE);\r
-            break;\r
-        case FCIDM_SHVIEW_CUT:\r
-            TRACE("Verb FCIDM_SHVIEW_CUT\n");\r
-            DoCopyOrCut(iface, lpcmi->hwnd, TRUE);\r
-            break;\r
-        default:\r
-            FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb));\r
-        }\r
-    }\r
-    else\r
-    {\r
-        TRACE("Verb is %s\n",debugstr_a(lpcmi->lpVerb));\r
-        if (strcmp(lpcmi->lpVerb,"delete")==0)\r
-            DoDelete(iface);\r
-        else\r
-            FIXME("Unhandled string verb %s\n",debugstr_a(lpcmi->lpVerb));\r
-    }\r
-    return NOERROR;\r
-}\r
-\r
-/**************************************************************************\r
-*  ISvItemCm_fnGetCommandString()\r
-*/\r
-static HRESULT WINAPI ISvItemCm_fnGetCommandString(\r
-       IContextMenu2 *iface,\r
-       UINT idCommand,\r
-       UINT uFlags,\r
-       UINT* lpReserved,\r
-       LPSTR lpszName,\r
-       UINT uMaxNameLen)\r
-{\r
-       ItemCmImpl *This = (ItemCmImpl *)iface;\r
-\r
-       HRESULT  hr = E_INVALIDARG;\r
-\r
-       TRACE("(%p)->(idcom=%x flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);\r
-\r
-       switch(uFlags)\r
-       {\r
-         case GCS_HELPTEXTA:\r
-         case GCS_HELPTEXTW:\r
-           hr = E_NOTIMPL;\r
-           break;\r
-\r
-         case GCS_VERBA:\r
-           switch(idCommand)\r
-           {\r
-             case FCIDM_SHVIEW_RENAME:\r
-               strcpy((LPSTR)lpszName, "rename");\r
-               hr = NOERROR;\r
-               break;\r
-           }\r
-           break;\r
-\r
-            /* NT 4.0 with IE 3.0x or no IE will always call This with GCS_VERBW. In This\r
-            case, you need to do the lstrcpyW to the pointer passed.*/\r
-         case GCS_VERBW:\r
-           switch(idCommand)\r
-           { case FCIDM_SHVIEW_RENAME:\r
-                MultiByteToWideChar( CP_ACP, 0, "rename", -1, (LPWSTR)lpszName, uMaxNameLen );\r
-               hr = NOERROR;\r
-               break;\r
-           }\r
-           break;\r
-\r
-         case GCS_VALIDATEA:\r
-         case GCS_VALIDATEW:\r
-           hr = NOERROR;\r
-           break;\r
-       }\r
-       TRACE("-- (%p)->(name=%s)\n",This, lpszName);\r
-       return hr;\r
-}\r
-\r
-/**************************************************************************\r
-* ISvItemCm_fnHandleMenuMsg()\r
-* NOTES\r
-*  should be only in IContextMenu2 and IContextMenu3\r
-*  is nevertheless called from word95\r
-*/\r
-static HRESULT WINAPI ISvItemCm_fnHandleMenuMsg(\r
-       IContextMenu2 *iface,\r
-       UINT uMsg,\r
-       WPARAM wParam,\r
-       LPARAM lParam)\r
-{\r
-       ItemCmImpl *This = (ItemCmImpl *)iface;\r
-\r
-       TRACE("(%p)->(msg=%x wp=%x lp=%lx)\n",This, uMsg, wParam, lParam);\r
-\r
-       return E_NOTIMPL;\r
-}\r
-\r
-static struct IContextMenu2Vtbl cmvt =\r
-{\r
-       ISvItemCm_fnQueryInterface,\r
-       ISvItemCm_fnAddRef,\r
-       ISvItemCm_fnRelease,\r
-       ISvItemCm_fnQueryContextMenu,\r
-       ISvItemCm_fnInvokeCommand,\r
-       ISvItemCm_fnGetCommandString,\r
-       ISvItemCm_fnHandleMenuMsg\r
-};\r
+/*
+ *     IContextMenu for items in the shellview
+ *
+ * Copyright 1998, 2000 Juergen Schmied <juergen.schmied@debitel.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "winerror.h"
+#include "wine/debug.h"
+
+#include "windef.h"
+#include "wingdi.h"
+#include "pidl.h"
+#include "shlguid.h"
+#include "undocshell.h"
+#include "shlobj.h"
+
+#include "shell32_main.h"
+#include "shellfolder.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(shell);
+
+/**************************************************************************
+*  IContextMenu Implementation
+*/
+typedef struct
+{      IContextMenu2Vtbl *lpVtbl;
+       DWORD           ref;
+       IShellFolder*   pSFParent;
+       LPITEMIDLIST    pidl;           /* root pidl */
+       LPITEMIDLIST    *apidl;         /* array of child pidls */
+       UINT            cidl;
+       BOOL            bAllValues;
+} ItemCmImpl;
+
+
+static struct IContextMenu2Vtbl cmvt;
+
+/**************************************************************************
+* ISvItemCm_CanRenameItems()
+*/
+static BOOL ISvItemCm_CanRenameItems(ItemCmImpl *This)
+{      UINT  i;
+       DWORD dwAttributes;
+
+       TRACE("(%p)->()\n",This);
+
+       if(This->apidl)
+       {
+         for(i = 0; i < This->cidl; i++){}
+         if(i > 1) return FALSE;               /* can't rename more than one item at a time*/
+         dwAttributes = SFGAO_CANRENAME;
+         IShellFolder_GetAttributesOf(This->pSFParent, 1, (LPCITEMIDLIST*)This->apidl, &dwAttributes);
+         return dwAttributes & SFGAO_CANRENAME;
+       }
+       return FALSE;
+}
+
+/**************************************************************************
+*   ISvItemCm_Constructor()
+*/
+IContextMenu2 *ISvItemCm_Constructor(LPSHELLFOLDER pSFParent, LPCITEMIDLIST pidl, LPCITEMIDLIST *apidl, UINT cidl)
+{      ItemCmImpl* cm;
+       UINT  u;
+
+       cm = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ItemCmImpl));
+       cm->lpVtbl = &cmvt;
+       cm->ref = 1;
+       cm->pidl = ILClone(pidl);
+       cm->pSFParent = pSFParent;
+
+       if(pSFParent) IShellFolder_AddRef(pSFParent);
+
+       cm->apidl = _ILCopyaPidl(apidl, cidl);
+       cm->cidl = cidl;
+
+       cm->bAllValues = 1;
+       for(u = 0; u < cidl; u++)
+       {
+         cm->bAllValues &= (_ILIsValue(apidl[u]) ? 1 : 0);
+       }
+
+       TRACE("(%p)->()\n",cm);
+
+       return (IContextMenu2*)cm;
+}
+
+/**************************************************************************
+*  ISvItemCm_fnQueryInterface
+*/
+static HRESULT WINAPI ISvItemCm_fnQueryInterface(IContextMenu2 *iface, REFIID riid, LPVOID *ppvObj)
+{
+       ItemCmImpl *This = (ItemCmImpl *)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;
+       }
+       else if(IsEqualIID(riid, &IID_IShellExtInit))  /*IShellExtInit*/
+       {
+         FIXME("-- LPSHELLEXTINIT pointer requested\n");
+       }
+
+       if(*ppvObj)
+       {
+         IUnknown_AddRef((IUnknown*)*ppvObj);
+         TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
+         return S_OK;
+       }
+       TRACE("-- Interface: E_NOINTERFACE\n");
+       return E_NOINTERFACE;
+}
+
+/**************************************************************************
+*  ISvItemCm_fnAddRef
+*/
+static ULONG WINAPI ISvItemCm_fnAddRef(IContextMenu2 *iface)
+{
+       ItemCmImpl *This = (ItemCmImpl *)iface;
+       ULONG refCount = InterlockedIncrement(&This->ref);
+
+       TRACE("(%p)->(count=%lu)\n", This, refCount - 1);
+
+       return refCount;
+}
+
+/**************************************************************************
+*  ISvItemCm_fnRelease
+*/
+static ULONG WINAPI ISvItemCm_fnRelease(IContextMenu2 *iface)
+{
+       ItemCmImpl *This = (ItemCmImpl *)iface;
+       ULONG refCount = InterlockedDecrement(&This->ref);
+
+       TRACE("(%p)->(count=%li)\n", This, refCount + 1);
+
+       if (!refCount)
+       {
+         TRACE(" destroying IContextMenu(%p)\n",This);
+
+         if(This->pSFParent)
+           IShellFolder_Release(This->pSFParent);
+
+         if(This->pidl)
+           SHFree(This->pidl);
+
+         /*make sure the pidl is freed*/
+         _ILFreeaPidl(This->apidl, This->cidl);
+
+         HeapFree(GetProcessHeap(),0,This);
+       }
+       return refCount;
+}
+
+/**************************************************************************
+*  ICM_InsertItem()
+*/
+void WINAPI _InsertMenuItem (
+       HMENU hmenu,
+       UINT indexMenu,
+       BOOL fByPosition,
+       UINT wID,
+       UINT fType,
+       LPSTR dwTypeData,
+       UINT fState)
+{
+       MENUITEMINFOA   mii;
+
+       ZeroMemory(&mii, sizeof(mii));
+       mii.cbSize = sizeof(mii);
+       if (fType == MFT_SEPARATOR)
+       {
+         mii.fMask = MIIM_ID | MIIM_TYPE;
+       }
+       else
+       {
+         mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
+         mii.dwTypeData = dwTypeData;
+         mii.fState = fState;
+       }
+       mii.wID = wID;
+       mii.fType = fType;
+       InsertMenuItemA( hmenu, indexMenu, fByPosition, &mii);
+}
+
+/**************************************************************************
+* ISvItemCm_fnQueryContextMenu()
+* FIXME: load menu MENU_SHV_FILE out of resources instead if creating
+*               each menu item by calling _InsertMenuItem()
+*/
+static HRESULT WINAPI ISvItemCm_fnQueryContextMenu(
+       IContextMenu2 *iface,
+       HMENU hmenu,
+       UINT indexMenu,
+       UINT idCmdFirst,
+       UINT idCmdLast,
+       UINT uFlags)
+{
+       ItemCmImpl *This = (ItemCmImpl *)iface;
+
+       TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",This, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
+
+       if (idCmdFirst != 0)
+         FIXME("We should use idCmdFirst=%d and idCmdLast=%d for command ids\n", idCmdFirst, idCmdLast);
+
+       if(!(CMF_DEFAULTONLY & uFlags) && This->cidl>0)
+       {
+         if(!(uFlags & CMF_EXPLORE))
+           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_OPEN, MFT_STRING, "&Select", MFS_ENABLED);
+
+         if(This->bAllValues)
+         {
+           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_OPEN, MFT_STRING, "&Open", MFS_ENABLED);
+           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_EXPLORE, MFT_STRING, "&Explore", MFS_ENABLED);
+         }
+         else
+         {
+           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_EXPLORE, MFT_STRING, "&Explore", MFS_ENABLED);
+           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_OPEN, MFT_STRING, "&Open", MFS_ENABLED);
+         }
+
+         SetMenuDefaultItem(hmenu, 0, MF_BYPOSITION);
+
+         _InsertMenuItem(hmenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+         _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_COPY, MFT_STRING, "&Copy", MFS_ENABLED);
+         _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_CUT, MFT_STRING, "&Cut", MFS_ENABLED);
+
+         _InsertMenuItem(hmenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+         _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_DELETE, MFT_STRING, "&Delete", MFS_ENABLED);
+
+         if(uFlags & CMF_CANRENAME)
+         {
+           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_RENAME, MFT_STRING, "&Rename", ISvItemCm_CanRenameItems(This) ? MFS_ENABLED : MFS_DISABLED);
+         }
+
+         _InsertMenuItem(hmenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+         _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_PROPERTIES, MFT_STRING, "&Properties::", MFS_ENABLED);
+
+
+         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (FCIDM_SHVIEWLAST));
+       }
+       return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
+}
+
+/**************************************************************************
+* DoOpenExplore
+*
+*  for folders only
+*/
+
+static void DoOpenExplore(
+       IContextMenu2 *iface,
+       HWND hwnd,
+       LPCSTR verb)
+{
+       ItemCmImpl *This = (ItemCmImpl *)iface;
+
+       UINT i, bFolderFound = FALSE;
+       LPITEMIDLIST    pidlFQ;
+       SHELLEXECUTEINFOA       sei;
+
+       /* Find the first item in the list that is not a value. These commands
+           should never be invoked if there isn't at least one folder item in the list.*/
+
+       for(i = 0; i<This->cidl; i++)
+       {
+         if(!_ILIsValue(This->apidl[i]))
+         {
+           bFolderFound = TRUE;
+           break;
+         }
+       }
+
+       if (!bFolderFound) return;
+
+       pidlFQ = ILCombine(This->pidl, This->apidl[i]);
+
+       ZeroMemory(&sei, sizeof(sei));
+       sei.cbSize = sizeof(sei);
+       sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME;
+       sei.lpIDList = pidlFQ;
+       sei.lpClass = "Folder";
+       sei.hwnd = hwnd;
+       sei.nShow = SW_SHOWNORMAL;
+       sei.lpVerb = verb;
+       ShellExecuteExA(&sei);
+       SHFree(pidlFQ);
+}
+
+/**************************************************************************
+* DoRename
+*/
+static void DoRename(
+       IContextMenu2 *iface,
+       HWND hwnd)
+{
+       ItemCmImpl *This = (ItemCmImpl *)iface;
+
+       LPSHELLBROWSER  lpSB;
+       LPSHELLVIEW     lpSV;
+
+       TRACE("(%p)->(wnd=%p)\n",This, hwnd);
+
+       /* get the active IShellView */
+       if ((lpSB = (LPSHELLBROWSER)SendMessageA(hwnd, CWM_GETISHELLBROWSER,0,0)))
+       {
+         if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))
+         {
+           TRACE("(sv=%p)\n",lpSV);
+           IShellView_SelectItem(lpSV, This->apidl[0],
+              SVSI_DESELECTOTHERS|SVSI_EDIT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_SELECT);
+           IShellView_Release(lpSV);
+         }
+       }
+}
+
+/**************************************************************************
+ * DoDelete
+ *
+ * deletes the currently selected items
+ */
+static void DoDelete(IContextMenu2 *iface)
+{
+       ItemCmImpl *This = (ItemCmImpl *)iface;
+       ISFHelper * psfhlp;
+
+       IShellFolder_QueryInterface(This->pSFParent, &IID_ISFHelper, (LPVOID*)&psfhlp);
+       if (psfhlp)
+       {
+         ISFHelper_DeleteItems(psfhlp, This->cidl, (LPCITEMIDLIST *)This->apidl);
+         ISFHelper_Release(psfhlp);
+       }
+}
+
+/**************************************************************************
+ * DoCopyOrCut
+ *
+ * copies the currently selected items into the clipboard
+ */
+static BOOL DoCopyOrCut(
+       IContextMenu2 *iface,
+       HWND hwnd,
+       BOOL bCut)
+{
+       ItemCmImpl *This = (ItemCmImpl *)iface;
+
+       LPSHELLBROWSER  lpSB;
+       LPSHELLVIEW     lpSV;
+       LPDATAOBJECT    lpDo;
+
+       TRACE("(%p)->(wnd=%p,bCut=0x%08x)\n",This, hwnd, bCut);
+
+       /* get the active IShellView */
+       if ((lpSB = (LPSHELLBROWSER)SendMessageA(hwnd, CWM_GETISHELLBROWSER,0,0)))
+       {
+         if (SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))
+         {
+           if (SUCCEEDED(IShellView_GetItemObject(lpSV, SVGIO_SELECTION, &IID_IDataObject, (LPVOID*)&lpDo)))
+           {
+             OleSetClipboard(lpDo);
+             IDataObject_Release(lpDo);
+           }
+           IShellView_Release(lpSV);
+         }
+       }
+       return TRUE;
+}
+/**************************************************************************
+* ISvItemCm_fnInvokeCommand()
+*/
+static HRESULT WINAPI ISvItemCm_fnInvokeCommand(
+       IContextMenu2 *iface,
+       LPCMINVOKECOMMANDINFO lpcmi)
+{
+    ItemCmImpl *This = (ItemCmImpl *)iface;
+
+    if (lpcmi->cbSize != sizeof(CMINVOKECOMMANDINFO))
+        FIXME("Is an EX structure\n");
+
+    TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);
+
+    if( HIWORD(lpcmi->lpVerb)==0 && LOWORD(lpcmi->lpVerb) > FCIDM_SHVIEWLAST)
+    {
+        TRACE("Invalid Verb %x\n",LOWORD(lpcmi->lpVerb));
+        return E_INVALIDARG;
+    }
+
+    if (HIWORD(lpcmi->lpVerb) == 0)
+    {
+        switch(LOWORD(lpcmi->lpVerb))
+        {
+        case FCIDM_SHVIEW_EXPLORE:
+            TRACE("Verb FCIDM_SHVIEW_EXPLORE\n");
+            DoOpenExplore(iface, lpcmi->hwnd, "explore");
+            break;
+        case FCIDM_SHVIEW_OPEN:
+            TRACE("Verb FCIDM_SHVIEW_OPEN\n");
+            DoOpenExplore(iface, lpcmi->hwnd, "open");
+            break;
+        case FCIDM_SHVIEW_RENAME:
+            TRACE("Verb FCIDM_SHVIEW_RENAME\n");
+            DoRename(iface, lpcmi->hwnd);
+            break;
+        case FCIDM_SHVIEW_DELETE:
+            TRACE("Verb FCIDM_SHVIEW_DELETE\n");
+            DoDelete(iface);
+            break;
+        case FCIDM_SHVIEW_COPY:
+            TRACE("Verb FCIDM_SHVIEW_COPY\n");
+            DoCopyOrCut(iface, lpcmi->hwnd, FALSE);
+            break;
+        case FCIDM_SHVIEW_CUT:
+            TRACE("Verb FCIDM_SHVIEW_CUT\n");
+            DoCopyOrCut(iface, lpcmi->hwnd, TRUE);
+            break;
+        case FCIDM_SHVIEW_PROPERTIES:
+            TRACE("Verb FCIDM_SHVIEW_PROPERTIES\n");
+            /* Open the property sheet page */
+            SHObjectProperties(NULL, TEXT("SHOP_FILEPATH"), lpcmi->hwnd, NULL);
+            break;
+        default:
+            FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb));
+        }
+    }
+    else
+    {
+        TRACE("Verb is %s\n",debugstr_a(lpcmi->lpVerb));
+        if (strcmp(lpcmi->lpVerb,"delete")==0)
+            DoDelete(iface);
+        else
+            FIXME("Unhandled string verb %s\n",debugstr_a(lpcmi->lpVerb));
+    }
+    return NOERROR;
+}
+
+/**************************************************************************
+*  ISvItemCm_fnGetCommandString()
+*/
+static HRESULT WINAPI ISvItemCm_fnGetCommandString(
+       IContextMenu2 *iface,
+       UINT idCommand,
+       UINT uFlags,
+       UINT* lpReserved,
+       LPSTR lpszName,
+       UINT uMaxNameLen)
+{
+       ItemCmImpl *This = (ItemCmImpl *)iface;
+
+       HRESULT  hr = E_INVALIDARG;
+
+       TRACE("(%p)->(idcom=%x flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
+
+       switch(uFlags)
+       {
+         case GCS_HELPTEXTA:
+         case GCS_HELPTEXTW:
+           hr = E_NOTIMPL;
+           break;
+
+         case GCS_VERBA:
+           switch(idCommand)
+           {
+             case FCIDM_SHVIEW_RENAME:
+               strcpy((LPSTR)lpszName, "rename");
+               hr = NOERROR;
+               break;
+           }
+           break;
+
+            /* NT 4.0 with IE 3.0x or no IE will always call This with GCS_VERBW. In This
+            case, you need to do the lstrcpyW to the pointer passed.*/
+         case GCS_VERBW:
+           switch(idCommand)
+           { case FCIDM_SHVIEW_RENAME:
+                MultiByteToWideChar( CP_ACP, 0, "rename", -1, (LPWSTR)lpszName, uMaxNameLen );
+               hr = NOERROR;
+               break;
+           }
+           break;
+
+         case GCS_VALIDATEA:
+         case GCS_VALIDATEW:
+           hr = NOERROR;
+           break;
+       }
+       TRACE("-- (%p)->(name=%s)\n",This, lpszName);
+       return hr;
+}
+
+/**************************************************************************
+* ISvItemCm_fnHandleMenuMsg()
+* NOTES
+*  should be only in IContextMenu2 and IContextMenu3
+*  is nevertheless called from word95
+*/
+static HRESULT WINAPI ISvItemCm_fnHandleMenuMsg(
+       IContextMenu2 *iface,
+       UINT uMsg,
+       WPARAM wParam,
+       LPARAM lParam)
+{
+       ItemCmImpl *This = (ItemCmImpl *)iface;
+
+       TRACE("(%p)->(msg=%x wp=%x lp=%lx)\n",This, uMsg, wParam, lParam);
+
+       return E_NOTIMPL;
+}
+
+static struct IContextMenu2Vtbl cmvt =
+{
+       ISvItemCm_fnQueryInterface,
+       ISvItemCm_fnAddRef,
+       ISvItemCm_fnRelease,
+       ISvItemCm_fnQueryContextMenu,
+       ISvItemCm_fnInvokeCommand,
+       ISvItemCm_fnGetCommandString,
+       ISvItemCm_fnHandleMenuMsg
+};