| /* | |
| * IContextMenu for items in the shellview | |
| * | |
| * Copyright 1998-2000 Juergen Schmied <juergen.schmied@debitel.net>, | |
| * <juergen.schmied@metronet.de> | |
| * | |
| * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include <string.h> | |
| #define COBJMACROS | |
| #define NONAMELESSUNION | |
| #include "winerror.h" | |
| #include "wine/debug.h" | |
| #include "windef.h" | |
| #include "wingdi.h" | |
| #include "pidl.h" | |
| #include "undocshell.h" | |
| #include "shlobj.h" | |
| #include "winreg.h" | |
| #include "prsht.h" | |
| #include "shell32_main.h" | |
| #include "shellfolder.h" | |
| #include "shresdef.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(shell); | |
| typedef struct | |
| { | |
| IContextMenu3 IContextMenu3_iface; | |
| LONG ref; | |
| IShellFolder* parent; | |
| /* item menu data */ | |
| LPITEMIDLIST pidl; /* root pidl */ | |
| LPITEMIDLIST *apidl; /* array of child pidls */ | |
| UINT cidl; | |
| BOOL allvalues; | |
| /* background menu data */ | |
| BOOL desktop; | |
| } ContextMenu; | |
| static inline ContextMenu *impl_from_IContextMenu3(IContextMenu3 *iface) | |
| { | |
| return CONTAINING_RECORD(iface, ContextMenu, IContextMenu3_iface); | |
| } | |
| static HRESULT WINAPI ContextMenu_QueryInterface(IContextMenu3 *iface, REFIID riid, LPVOID *ppvObj) | |
| { | |
| ContextMenu *This = impl_from_IContextMenu3(iface); | |
| TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObj); | |
| *ppvObj = NULL; | |
| if (IsEqualIID(riid, &IID_IUnknown) || | |
| IsEqualIID(riid, &IID_IContextMenu) || | |
| IsEqualIID(riid, &IID_IContextMenu2) || | |
| IsEqualIID(riid, &IID_IContextMenu3)) | |
| { | |
| *ppvObj = &This->IContextMenu3_iface; | |
| } | |
| else if (IsEqualIID(riid, &IID_IShellExtInit)) /*IShellExtInit*/ | |
| { | |
| FIXME("-- LPSHELLEXTINIT pointer requested\n"); | |
| } | |
| if(*ppvObj) | |
| { | |
| IContextMenu3_AddRef(iface); | |
| return S_OK; | |
| } | |
| TRACE("-- Interface: E_NOINTERFACE\n"); | |
| return E_NOINTERFACE; | |
| } | |
| static ULONG WINAPI ContextMenu_AddRef(IContextMenu3 *iface) | |
| { | |
| ContextMenu *This = impl_from_IContextMenu3(iface); | |
| ULONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p)->(%u)\n", This, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI ContextMenu_Release(IContextMenu3 *iface) | |
| { | |
| ContextMenu *This = impl_from_IContextMenu3(iface); | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p)->(%u)\n", This, ref); | |
| if (!ref) | |
| { | |
| if(This->parent) | |
| IShellFolder_Release(This->parent); | |
| SHFree(This->pidl); | |
| _ILFreeaPidl(This->apidl, This->cidl); | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI ItemMenu_QueryContextMenu( | |
| IContextMenu3 *iface, | |
| HMENU hmenu, | |
| UINT indexMenu, | |
| UINT idCmdFirst, | |
| UINT idCmdLast, | |
| UINT uFlags) | |
| { | |
| ContextMenu *This = impl_from_IContextMenu3(iface); | |
| INT uIDMax; | |
| TRACE("(%p)->(%p %d 0x%x 0x%x 0x%x )\n", This, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags); | |
| if(!(CMF_DEFAULTONLY & uFlags) && This->cidl > 0) | |
| { | |
| HMENU hmenures = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(MENU_SHV_FILE)); | |
| if(uFlags & CMF_EXPLORE) | |
| RemoveMenu(hmenures, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND); | |
| uIDMax = Shell_MergeMenus(hmenu, GetSubMenu(hmenures, 0), indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS); | |
| DestroyMenu(hmenures); | |
| if(This->allvalues) | |
| { | |
| MENUITEMINFOW mi; | |
| WCHAR str[255]; | |
| mi.cbSize = sizeof(mi); | |
| mi.fMask = MIIM_ID | MIIM_STRING | MIIM_FTYPE; | |
| mi.dwTypeData = str; | |
| mi.cch = 255; | |
| GetMenuItemInfoW(hmenu, FCIDM_SHVIEW_EXPLORE, MF_BYCOMMAND, &mi); | |
| RemoveMenu(hmenu, FCIDM_SHVIEW_EXPLORE + idCmdFirst, MF_BYCOMMAND); | |
| mi.cbSize = sizeof(mi); | |
| mi.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_STRING; | |
| mi.dwTypeData = str; | |
| mi.fState = MFS_ENABLED; | |
| mi.wID = FCIDM_SHVIEW_EXPLORE; | |
| mi.fType = MFT_STRING; | |
| InsertMenuItemW(hmenu, (uFlags & CMF_EXPLORE) ? 1 : 2, MF_BYPOSITION, &mi); | |
| } | |
| SetMenuDefaultItem(hmenu, 0, MF_BYPOSITION); | |
| if(uFlags & ~CMF_CANRENAME) | |
| RemoveMenu(hmenu, FCIDM_SHVIEW_RENAME, MF_BYCOMMAND); | |
| else | |
| { | |
| UINT enable = MF_BYCOMMAND; | |
| /* can't rename more than one item at a time*/ | |
| if (!This->apidl || This->cidl > 1) | |
| enable |= MFS_DISABLED; | |
| else | |
| { | |
| DWORD attr = SFGAO_CANRENAME; | |
| IShellFolder_GetAttributesOf(This->parent, 1, (LPCITEMIDLIST*)This->apidl, &attr); | |
| enable |= (attr & SFGAO_CANRENAME) ? MFS_ENABLED : MFS_DISABLED; | |
| } | |
| EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, enable); | |
| } | |
| return MAKE_HRESULT(SEVERITY_SUCCESS, 0, uIDMax-idCmdFirst); | |
| } | |
| return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0); | |
| } | |
| /************************************************************************** | |
| * DoOpenExplore | |
| * | |
| * for folders only | |
| */ | |
| static void DoOpenExplore(ContextMenu *This, HWND hwnd, LPCSTR verb) | |
| { | |
| UINT i; | |
| BOOL 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); | |
| } | |
| /************************************************************************** | |
| * DoDelete | |
| * | |
| * deletes the currently selected items | |
| */ | |
| static void DoDelete(ContextMenu *This) | |
| { | |
| ISFHelper *helper; | |
| IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&helper); | |
| if (helper) | |
| { | |
| ISFHelper_DeleteItems(helper, This->cidl, (LPCITEMIDLIST*)This->apidl); | |
| ISFHelper_Release(helper); | |
| } | |
| } | |
| /************************************************************************** | |
| * DoCopyOrCut | |
| * | |
| * copies the currently selected items into the clipboard | |
| */ | |
| static void DoCopyOrCut(ContextMenu *This, HWND hwnd, BOOL cut) | |
| { | |
| IDataObject *dataobject; | |
| TRACE("(%p)->(wnd=%p, cut=%d)\n", This, hwnd, cut); | |
| if (SUCCEEDED(IShellFolder_GetUIObjectOf(This->parent, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl, &IID_IDataObject, 0, (void**)&dataobject))) | |
| { | |
| OleSetClipboard(dataobject); | |
| IDataObject_Release(dataobject); | |
| } | |
| } | |
| /************************************************************************** | |
| * Properties_AddPropSheetCallback | |
| * | |
| * Used by DoOpenProperties through SHCreatePropSheetExtArrayEx to add | |
| * propertysheet pages from shell extensions. | |
| */ | |
| static BOOL CALLBACK Properties_AddPropSheetCallback(HPROPSHEETPAGE hpage, LPARAM lparam) | |
| { | |
| LPPROPSHEETHEADERW psh = (LPPROPSHEETHEADERW) lparam; | |
| psh->u3.phpage[psh->nPages++] = hpage; | |
| return TRUE; | |
| } | |
| #define MAX_PROP_PAGES 99 | |
| static void DoOpenProperties(ContextMenu *This, HWND hwnd) | |
| { | |
| static const WCHAR wszFolder[] = {'F','o','l','d','e','r', 0}; | |
| static const WCHAR wszFiletypeAll[] = {'*',0}; | |
| LPSHELLFOLDER lpDesktopSF; | |
| LPSHELLFOLDER lpSF; | |
| LPDATAOBJECT lpDo; | |
| WCHAR wszFiletype[MAX_PATH]; | |
| WCHAR wszFilename[MAX_PATH]; | |
| PROPSHEETHEADERW psh; | |
| HPROPSHEETPAGE hpages[MAX_PROP_PAGES]; | |
| HPSXA hpsxa; | |
| UINT ret; | |
| TRACE("(%p)->(wnd=%p)\n", This, hwnd); | |
| ZeroMemory(&psh, sizeof(PROPSHEETHEADERW)); | |
| psh.dwSize = sizeof (PROPSHEETHEADERW); | |
| psh.hwndParent = hwnd; | |
| psh.dwFlags = PSH_PROPTITLE; | |
| psh.nPages = 0; | |
| psh.u3.phpage = hpages; | |
| psh.u2.nStartPage = 0; | |
| _ILSimpleGetTextW(This->apidl[0], (LPVOID)wszFilename, MAX_PATH); | |
| psh.pszCaption = (LPCWSTR)wszFilename; | |
| /* Find out where to look for the shell extensions */ | |
| if (_ILIsValue(This->apidl[0])) | |
| { | |
| char sTemp[64]; | |
| sTemp[0] = 0; | |
| if (_ILGetExtension(This->apidl[0], sTemp, 64)) | |
| { | |
| HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE); | |
| MultiByteToWideChar(CP_ACP, 0, sTemp, -1, wszFiletype, MAX_PATH); | |
| } | |
| else | |
| { | |
| wszFiletype[0] = 0; | |
| } | |
| } | |
| else if (_ILIsFolder(This->apidl[0])) | |
| { | |
| lstrcpynW(wszFiletype, wszFolder, 64); | |
| } | |
| else if (_ILIsSpecialFolder(This->apidl[0])) | |
| { | |
| LPGUID folderGUID; | |
| static const WCHAR wszclsid[] = {'C','L','S','I','D','\\', 0}; | |
| folderGUID = _ILGetGUIDPointer(This->apidl[0]); | |
| lstrcpyW(wszFiletype, wszclsid); | |
| StringFromGUID2(folderGUID, &wszFiletype[6], MAX_PATH - 6); | |
| } | |
| else | |
| { | |
| FIXME("Requested properties for unknown type.\n"); | |
| return; | |
| } | |
| /* Get a suitable DataObject for accessing the files */ | |
| SHGetDesktopFolder(&lpDesktopSF); | |
| if (_ILIsPidlSimple(This->pidl)) | |
| { | |
| ret = IShellFolder_GetUIObjectOf(lpDesktopSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl, | |
| &IID_IDataObject, NULL, (LPVOID *)&lpDo); | |
| IShellFolder_Release(lpDesktopSF); | |
| } | |
| else | |
| { | |
| IShellFolder_BindToObject(lpDesktopSF, This->pidl, NULL, &IID_IShellFolder, (LPVOID*) &lpSF); | |
| ret = IShellFolder_GetUIObjectOf(lpSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl, | |
| &IID_IDataObject, NULL, (LPVOID *)&lpDo); | |
| IShellFolder_Release(lpSF); | |
| IShellFolder_Release(lpDesktopSF); | |
| } | |
| if (SUCCEEDED(ret)) | |
| { | |
| hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletype, MAX_PROP_PAGES - psh.nPages, lpDo); | |
| if (hpsxa != NULL) | |
| { | |
| SHAddFromPropSheetExtArray(hpsxa, Properties_AddPropSheetCallback, (LPARAM)&psh); | |
| SHDestroyPropSheetExtArray(hpsxa); | |
| } | |
| hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletypeAll, MAX_PROP_PAGES - psh.nPages, lpDo); | |
| if (hpsxa != NULL) | |
| { | |
| SHAddFromPropSheetExtArray(hpsxa, Properties_AddPropSheetCallback, (LPARAM)&psh); | |
| SHDestroyPropSheetExtArray(hpsxa); | |
| } | |
| IDataObject_Release(lpDo); | |
| } | |
| if (psh.nPages) | |
| PropertySheetW(&psh); | |
| else | |
| FIXME("No property pages found.\n"); | |
| } | |
| static HRESULT WINAPI ItemMenu_InvokeCommand( | |
| IContextMenu3 *iface, | |
| LPCMINVOKECOMMANDINFO lpcmi) | |
| { | |
| ContextMenu *This = impl_from_IContextMenu3(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 (IS_INTRESOURCE(lpcmi->lpVerb) && LOWORD(lpcmi->lpVerb) > FCIDM_SHVIEWLAST) | |
| { | |
| TRACE("Invalid Verb %x\n", LOWORD(lpcmi->lpVerb)); | |
| return E_INVALIDARG; | |
| } | |
| if (IS_INTRESOURCE(lpcmi->lpVerb)) | |
| { | |
| switch(LOWORD(lpcmi->lpVerb)) | |
| { | |
| case FCIDM_SHVIEW_EXPLORE: | |
| TRACE("Verb FCIDM_SHVIEW_EXPLORE\n"); | |
| DoOpenExplore(This, lpcmi->hwnd, "explore"); | |
| break; | |
| case FCIDM_SHVIEW_OPEN: | |
| TRACE("Verb FCIDM_SHVIEW_OPEN\n"); | |
| DoOpenExplore(This, lpcmi->hwnd, "open"); | |
| break; | |
| case FCIDM_SHVIEW_RENAME: | |
| { | |
| IShellBrowser *browser; | |
| /* get the active IShellView */ | |
| browser = (IShellBrowser*)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0); | |
| if (browser) | |
| { | |
| IShellView *view; | |
| if(SUCCEEDED(IShellBrowser_QueryActiveShellView(browser, &view))) | |
| { | |
| TRACE("(shellview=%p)\n", view); | |
| IShellView_SelectItem(view, This->apidl[0], | |
| SVSI_DESELECTOTHERS|SVSI_EDIT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_SELECT); | |
| IShellView_Release(view); | |
| } | |
| } | |
| break; | |
| } | |
| case FCIDM_SHVIEW_DELETE: | |
| TRACE("Verb FCIDM_SHVIEW_DELETE\n"); | |
| DoDelete(This); | |
| break; | |
| case FCIDM_SHVIEW_COPY: | |
| TRACE("Verb FCIDM_SHVIEW_COPY\n"); | |
| DoCopyOrCut(This, lpcmi->hwnd, FALSE); | |
| break; | |
| case FCIDM_SHVIEW_CUT: | |
| TRACE("Verb FCIDM_SHVIEW_CUT\n"); | |
| DoCopyOrCut(This, lpcmi->hwnd, TRUE); | |
| break; | |
| case FCIDM_SHVIEW_PROPERTIES: | |
| TRACE("Verb FCIDM_SHVIEW_PROPERTIES\n"); | |
| DoOpenProperties(This, lpcmi->hwnd); | |
| break; | |
| default: | |
| FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb)); | |
| return E_INVALIDARG; | |
| } | |
| } | |
| else | |
| { | |
| TRACE("Verb is %s\n",debugstr_a(lpcmi->lpVerb)); | |
| if (strcmp(lpcmi->lpVerb,"delete")==0) | |
| DoDelete(This); | |
| else if (strcmp(lpcmi->lpVerb,"properties")==0) | |
| DoOpenProperties(This, lpcmi->hwnd); | |
| else { | |
| FIXME("Unhandled string verb %s\n",debugstr_a(lpcmi->lpVerb)); | |
| return E_FAIL; | |
| } | |
| } | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI ItemMenu_GetCommandString( | |
| IContextMenu3 *iface, | |
| UINT_PTR idCommand, | |
| UINT uFlags, | |
| UINT* lpReserved, | |
| LPSTR lpszName, | |
| UINT uMaxNameLen) | |
| { | |
| ContextMenu *This = impl_from_IContextMenu3(iface); | |
| HRESULT hr = E_INVALIDARG; | |
| TRACE("(%p)->(%lx 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_OPEN: | |
| strcpy(lpszName, "open"); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_EXPLORE: | |
| strcpy(lpszName, "explore"); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_CUT: | |
| strcpy(lpszName, "cut"); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_COPY: | |
| strcpy(lpszName, "copy"); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_CREATELINK: | |
| strcpy(lpszName, "link"); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_DELETE: | |
| strcpy(lpszName, "delete"); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_PROPERTIES: | |
| strcpy(lpszName, "properties"); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_RENAME: | |
| strcpy(lpszName, "rename"); | |
| hr = S_OK; | |
| 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_OPEN: | |
| MultiByteToWideChar(CP_ACP, 0, "open", -1, (LPWSTR)lpszName, uMaxNameLen); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_EXPLORE: | |
| MultiByteToWideChar(CP_ACP, 0, "explore", -1, (LPWSTR)lpszName, uMaxNameLen); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_CUT: | |
| MultiByteToWideChar(CP_ACP, 0, "cut", -1, (LPWSTR)lpszName, uMaxNameLen); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_COPY: | |
| MultiByteToWideChar(CP_ACP, 0, "copy", -1, (LPWSTR)lpszName, uMaxNameLen); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_CREATELINK: | |
| MultiByteToWideChar(CP_ACP, 0, "link", -1, (LPWSTR)lpszName, uMaxNameLen); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_DELETE: | |
| MultiByteToWideChar(CP_ACP, 0, "delete", -1, (LPWSTR)lpszName, uMaxNameLen); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_PROPERTIES: | |
| MultiByteToWideChar(CP_ACP, 0, "properties", -1, (LPWSTR)lpszName, uMaxNameLen); | |
| hr = S_OK; | |
| break; | |
| case FCIDM_SHVIEW_RENAME: | |
| MultiByteToWideChar( CP_ACP, 0, "rename", -1, (LPWSTR)lpszName, uMaxNameLen ); | |
| hr = S_OK; | |
| break; | |
| } | |
| break; | |
| case GCS_VALIDATEA: | |
| case GCS_VALIDATEW: | |
| hr = S_OK; | |
| break; | |
| } | |
| TRACE("-- (%p)->(name=%s)\n", This, lpszName); | |
| return hr; | |
| } | |
| /************************************************************************** | |
| * NOTES | |
| * should be only in IContextMenu2 and IContextMenu3 | |
| * is nevertheless called from word95 | |
| */ | |
| static HRESULT WINAPI ContextMenu_HandleMenuMsg(IContextMenu3 *iface, UINT msg, | |
| WPARAM wParam, LPARAM lParam) | |
| { | |
| ContextMenu *This = impl_from_IContextMenu3(iface); | |
| FIXME("(%p)->(0x%x 0x%lx 0x%lx): stub\n", This, msg, wParam, lParam); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI ContextMenu_HandleMenuMsg2(IContextMenu3 *iface, UINT msg, | |
| WPARAM wParam, LPARAM lParam, LRESULT *result) | |
| { | |
| ContextMenu *This = impl_from_IContextMenu3(iface); | |
| FIXME("(%p)->(0x%x 0x%lx 0x%lx %p): stub\n", This, msg, wParam, lParam, result); | |
| return E_NOTIMPL; | |
| } | |
| static const IContextMenu3Vtbl ItemContextMenuVtbl = | |
| { | |
| ContextMenu_QueryInterface, | |
| ContextMenu_AddRef, | |
| ContextMenu_Release, | |
| ItemMenu_QueryContextMenu, | |
| ItemMenu_InvokeCommand, | |
| ItemMenu_GetCommandString, | |
| ContextMenu_HandleMenuMsg, | |
| ContextMenu_HandleMenuMsg2 | |
| }; | |
| HRESULT ItemMenu_Constructor(IShellFolder *parent, LPCITEMIDLIST pidl, const LPCITEMIDLIST *apidl, UINT cidl, | |
| REFIID riid, void **pObj) | |
| { | |
| ContextMenu* This; | |
| HRESULT hr; | |
| UINT i; | |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); | |
| if (!This) return E_OUTOFMEMORY; | |
| This->IContextMenu3_iface.lpVtbl = &ItemContextMenuVtbl; | |
| This->ref = 1; | |
| This->parent = parent; | |
| if (parent) IShellFolder_AddRef(parent); | |
| This->pidl = ILClone(pidl); | |
| This->apidl = _ILCopyaPidl(apidl, cidl); | |
| This->cidl = cidl; | |
| This->allvalues = TRUE; | |
| This->desktop = FALSE; | |
| for (i = 0; i < cidl; i++) | |
| This->allvalues &= (_ILIsValue(apidl[i]) ? 1 : 0); | |
| hr = IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, pObj); | |
| IContextMenu3_Release(&This->IContextMenu3_iface); | |
| return hr; | |
| } | |
| /* Background menu implementation */ | |
| static HRESULT WINAPI BackgroundMenu_QueryContextMenu( | |
| IContextMenu3 *iface, | |
| HMENU hMenu, | |
| UINT indexMenu, | |
| UINT idCmdFirst, | |
| UINT idCmdLast, | |
| UINT uFlags) | |
| { | |
| ContextMenu *This = impl_from_IContextMenu3(iface); | |
| HMENU hMyMenu; | |
| UINT idMax; | |
| HRESULT hr; | |
| TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n", | |
| This, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags); | |
| hMyMenu = LoadMenuA(shell32_hInstance, "MENU_002"); | |
| if (uFlags & CMF_DEFAULTONLY) | |
| { | |
| HMENU ourMenu = GetSubMenu(hMyMenu,0); | |
| UINT oldDef = GetMenuDefaultItem(hMenu,TRUE,GMDI_USEDISABLED); | |
| UINT newDef = GetMenuDefaultItem(ourMenu,TRUE,GMDI_USEDISABLED); | |
| if (newDef != oldDef) | |
| SetMenuDefaultItem(hMenu,newDef,TRUE); | |
| if (newDef!=0xFFFFFFFF) | |
| hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, newDef+1); | |
| else | |
| hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0); | |
| } | |
| else | |
| { | |
| idMax = Shell_MergeMenus (hMenu, GetSubMenu(hMyMenu,0), indexMenu, | |
| idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS); | |
| hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, idMax-idCmdFirst); | |
| } | |
| DestroyMenu(hMyMenu); | |
| TRACE("(%p)->returning 0x%x\n",This,hr); | |
| return hr; | |
| } | |
| static void DoNewFolder(ContextMenu *This, IShellView *view) | |
| { | |
| ISFHelper *helper; | |
| IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&helper); | |
| if (helper) | |
| { | |
| WCHAR nameW[MAX_PATH]; | |
| LPITEMIDLIST pidl; | |
| ISFHelper_GetUniqueName(helper, nameW, MAX_PATH); | |
| ISFHelper_AddFolder(helper, 0, nameW, &pidl); | |
| if (view) | |
| { | |
| /* if we are in a shellview do labeledit */ | |
| IShellView_SelectItem(view, | |
| pidl,(SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE | |
| |SVSI_FOCUSED|SVSI_SELECT)); | |
| } | |
| SHFree(pidl); | |
| ISFHelper_Release(helper); | |
| } | |
| } | |
| static BOOL DoPaste(ContextMenu *This) | |
| { | |
| BOOL bSuccess = FALSE; | |
| IDataObject * pda; | |
| TRACE("\n"); | |
| if(SUCCEEDED(OleGetClipboard(&pda))) | |
| { | |
| STGMEDIUM medium; | |
| FORMATETC formatetc; | |
| TRACE("pda=%p\n", pda); | |
| /* Set the FORMATETC structure*/ | |
| InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLISTW), TYMED_HGLOBAL); | |
| /* Get the pidls from IDataObject */ | |
| if(SUCCEEDED(IDataObject_GetData(pda,&formatetc,&medium))) | |
| { | |
| LPITEMIDLIST * apidl; | |
| LPITEMIDLIST pidl; | |
| IShellFolder *psfFrom = NULL, *psfDesktop; | |
| LPIDA lpcida = GlobalLock(medium.u.hGlobal); | |
| TRACE("cida=%p\n", lpcida); | |
| apidl = _ILCopyCidaToaPidl(&pidl, lpcida); | |
| /* bind to the source shellfolder */ | |
| SHGetDesktopFolder(&psfDesktop); | |
| if(psfDesktop) | |
| { | |
| IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (LPVOID*)&psfFrom); | |
| IShellFolder_Release(psfDesktop); | |
| } | |
| if (psfFrom) | |
| { | |
| /* get source and destination shellfolder */ | |
| ISFHelper *psfhlpdst, *psfhlpsrc; | |
| IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&psfhlpdst); | |
| IShellFolder_QueryInterface(psfFrom, &IID_ISFHelper, (void**)&psfhlpsrc); | |
| /* do the copy/move */ | |
| if (psfhlpdst && psfhlpsrc) | |
| { | |
| ISFHelper_CopyItems(psfhlpdst, psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl); | |
| /* FIXME handle move | |
| ISFHelper_DeleteItems(psfhlpsrc, lpcida->cidl, apidl); | |
| */ | |
| } | |
| if(psfhlpdst) ISFHelper_Release(psfhlpdst); | |
| if(psfhlpsrc) ISFHelper_Release(psfhlpsrc); | |
| IShellFolder_Release(psfFrom); | |
| } | |
| _ILFreeaPidl(apidl, lpcida->cidl); | |
| SHFree(pidl); | |
| /* release the medium*/ | |
| ReleaseStgMedium(&medium); | |
| } | |
| IDataObject_Release(pda); | |
| } | |
| #if 0 | |
| HGLOBAL hMem; | |
| OpenClipboard(NULL); | |
| hMem = GetClipboardData(CF_HDROP); | |
| if(hMem) | |
| { | |
| char * pDropFiles = GlobalLock(hMem); | |
| if(pDropFiles) | |
| { | |
| int len, offset = sizeof(DROPFILESTRUCT); | |
| while( pDropFiles[offset] != 0) | |
| { | |
| len = strlen(pDropFiles + offset); | |
| TRACE("%s\n", pDropFiles + offset); | |
| offset += len+1; | |
| } | |
| } | |
| GlobalUnlock(hMem); | |
| } | |
| CloseClipboard(); | |
| #endif | |
| return bSuccess; | |
| } | |
| static HRESULT WINAPI BackgroundMenu_InvokeCommand( | |
| IContextMenu3 *iface, | |
| LPCMINVOKECOMMANDINFO lpcmi) | |
| { | |
| ContextMenu *This = impl_from_IContextMenu3(iface); | |
| IShellBrowser *browser; | |
| IShellView *view = NULL; | |
| HWND hWnd = NULL; | |
| TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", This, lpcmi, lpcmi->lpVerb, lpcmi->hwnd); | |
| /* get the active IShellView */ | |
| if ((browser = (IShellBrowser*)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0))) | |
| { | |
| if (SUCCEEDED(IShellBrowser_QueryActiveShellView(browser, &view))) | |
| IShellView_GetWindow(view, &hWnd); | |
| } | |
| if(HIWORD(lpcmi->lpVerb)) | |
| { | |
| TRACE("%s\n", debugstr_a(lpcmi->lpVerb)); | |
| if (!strcmp(lpcmi->lpVerb, CMDSTR_NEWFOLDERA)) | |
| { | |
| DoNewFolder(This, view); | |
| } | |
| else if (!strcmp(lpcmi->lpVerb, CMDSTR_VIEWLISTA)) | |
| { | |
| if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_LISTVIEW, 0), 0); | |
| } | |
| else if (!strcmp(lpcmi->lpVerb, CMDSTR_VIEWDETAILSA)) | |
| { | |
| if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_REPORTVIEW, 0), 0); | |
| } | |
| else | |
| { | |
| FIXME("please report: unknown verb %s\n", debugstr_a(lpcmi->lpVerb)); | |
| } | |
| } | |
| else | |
| { | |
| switch (LOWORD(lpcmi->lpVerb)) | |
| { | |
| case FCIDM_SHVIEW_REFRESH: | |
| if (view) IShellView_Refresh(view); | |
| break; | |
| case FCIDM_SHVIEW_NEWFOLDER: | |
| DoNewFolder(This, view); | |
| break; | |
| case FCIDM_SHVIEW_INSERT: | |
| DoPaste(This); | |
| break; | |
| case FCIDM_SHVIEW_PROPERTIES: | |
| if (This->desktop) { | |
| ShellExecuteA(lpcmi->hwnd, "open", "rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL); | |
| } else { | |
| FIXME("launch item properties dialog\n"); | |
| } | |
| break; | |
| default: | |
| /* if it's an id just pass it to the parent shv */ | |
| if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0); | |
| break; | |
| } | |
| } | |
| if (view) | |
| IShellView_Release(view); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI BackgroundMenu_GetCommandString( | |
| IContextMenu3 *iface, | |
| UINT_PTR idCommand, | |
| UINT uFlags, | |
| UINT* lpReserved, | |
| LPSTR lpszName, | |
| UINT uMaxNameLen) | |
| { | |
| ContextMenu *This = impl_from_IContextMenu3(iface); | |
| TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen); | |
| /* test the existence of the menu items, the file dialog enables | |
| the buttons according to this */ | |
| if (uFlags == GCS_VALIDATEA) | |
| { | |
| if(HIWORD(idCommand)) | |
| { | |
| if (!strcmp((LPSTR)idCommand, CMDSTR_VIEWLISTA) || | |
| !strcmp((LPSTR)idCommand, CMDSTR_VIEWDETAILSA) || | |
| !strcmp((LPSTR)idCommand, CMDSTR_NEWFOLDERA)) | |
| { | |
| return S_OK; | |
| } | |
| } | |
| } | |
| FIXME("unknown command string\n"); | |
| return E_FAIL; | |
| } | |
| static const IContextMenu3Vtbl BackgroundContextMenuVtbl = | |
| { | |
| ContextMenu_QueryInterface, | |
| ContextMenu_AddRef, | |
| ContextMenu_Release, | |
| BackgroundMenu_QueryContextMenu, | |
| BackgroundMenu_InvokeCommand, | |
| BackgroundMenu_GetCommandString, | |
| ContextMenu_HandleMenuMsg, | |
| ContextMenu_HandleMenuMsg2 | |
| }; | |
| HRESULT BackgroundMenu_Constructor(IShellFolder *parent, BOOL desktop, REFIID riid, void **pObj) | |
| { | |
| ContextMenu *This; | |
| HRESULT hr; | |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); | |
| if (!This) return E_OUTOFMEMORY; | |
| This->IContextMenu3_iface.lpVtbl = &BackgroundContextMenuVtbl; | |
| This->ref = 1; | |
| This->parent = parent; | |
| This->pidl = NULL; | |
| This->apidl = NULL; | |
| This->cidl = 0; | |
| This->allvalues = FALSE; | |
| This->desktop = desktop; | |
| if (parent) IShellFolder_AddRef(parent); | |
| hr = IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, pObj); | |
| IContextMenu3_Release(&This->IContextMenu3_iface); | |
| return hr; | |
| } |