winecoreaudio: Fix a potential leak. (Clang).
[wine/wine-gecko.git] / dlls / shell32 / shlview_cmenu.c
blobfb4ef4ebc559f5aa8e5aa5db3bab101f8d7fa11c
1 /*
2 * IContextMenu for items in the shellview
4 * Copyright 1998-2000 Juergen Schmied <juergen.schmied@debitel.net>,
5 * <juergen.schmied@metronet.de>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <string.h>
24 #define COBJMACROS
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
28 #include "winerror.h"
29 #include "wine/debug.h"
31 #include "windef.h"
32 #include "wingdi.h"
33 #include "pidl.h"
34 #include "undocshell.h"
35 #include "shlobj.h"
36 #include "winreg.h"
37 #include "prsht.h"
39 #include "shell32_main.h"
40 #include "shellfolder.h"
42 #include "shresdef.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(shell);
46 typedef struct
48 IContextMenu3 IContextMenu3_iface;
49 LONG ref;
51 IShellFolder* parent;
53 /* item menu data */
54 LPITEMIDLIST pidl; /* root pidl */
55 LPITEMIDLIST *apidl; /* array of child pidls */
56 UINT cidl;
57 BOOL allvalues;
59 /* background menu data */
60 BOOL desktop;
61 } ContextMenu;
63 static inline ContextMenu *impl_from_IContextMenu3(IContextMenu3 *iface)
65 return CONTAINING_RECORD(iface, ContextMenu, IContextMenu3_iface);
68 static HRESULT WINAPI ContextMenu_QueryInterface(IContextMenu3 *iface, REFIID riid, LPVOID *ppvObj)
70 ContextMenu *This = impl_from_IContextMenu3(iface);
72 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObj);
74 *ppvObj = NULL;
76 if (IsEqualIID(riid, &IID_IUnknown) ||
77 IsEqualIID(riid, &IID_IContextMenu) ||
78 IsEqualIID(riid, &IID_IContextMenu2) ||
79 IsEqualIID(riid, &IID_IContextMenu3))
81 *ppvObj = &This->IContextMenu3_iface;
83 else if (IsEqualIID(riid, &IID_IShellExtInit)) /*IShellExtInit*/
85 FIXME("-- LPSHELLEXTINIT pointer requested\n");
88 if(*ppvObj)
90 IContextMenu3_AddRef(iface);
91 return S_OK;
94 TRACE("-- Interface: E_NOINTERFACE\n");
95 return E_NOINTERFACE;
98 static ULONG WINAPI ContextMenu_AddRef(IContextMenu3 *iface)
100 ContextMenu *This = impl_from_IContextMenu3(iface);
101 ULONG ref = InterlockedIncrement(&This->ref);
102 TRACE("(%p)->(%u)\n", This, ref);
103 return ref;
106 static ULONG WINAPI ContextMenu_Release(IContextMenu3 *iface)
108 ContextMenu *This = impl_from_IContextMenu3(iface);
109 ULONG ref = InterlockedDecrement(&This->ref);
111 TRACE("(%p)->(%u)\n", This, ref);
113 if (!ref)
115 if(This->parent)
116 IShellFolder_Release(This->parent);
118 SHFree(This->pidl);
119 _ILFreeaPidl(This->apidl, This->cidl);
121 HeapFree(GetProcessHeap(), 0, This);
124 return ref;
127 static HRESULT WINAPI ItemMenu_QueryContextMenu(
128 IContextMenu3 *iface,
129 HMENU hmenu,
130 UINT indexMenu,
131 UINT idCmdFirst,
132 UINT idCmdLast,
133 UINT uFlags)
135 ContextMenu *This = impl_from_IContextMenu3(iface);
136 INT uIDMax;
138 TRACE("(%p)->(%p %d 0x%x 0x%x 0x%x )\n", This, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
140 if(!(CMF_DEFAULTONLY & uFlags) && This->cidl > 0)
142 HMENU hmenures = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(MENU_SHV_FILE));
144 if(uFlags & CMF_EXPLORE)
145 RemoveMenu(hmenures, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
147 uIDMax = Shell_MergeMenus(hmenu, GetSubMenu(hmenures, 0), indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS);
149 DestroyMenu(hmenures);
151 if(This->allvalues)
153 MENUITEMINFOW mi;
154 WCHAR str[255];
155 mi.cbSize = sizeof(mi);
156 mi.fMask = MIIM_ID | MIIM_STRING | MIIM_FTYPE;
157 mi.dwTypeData = str;
158 mi.cch = 255;
159 GetMenuItemInfoW(hmenu, FCIDM_SHVIEW_EXPLORE, MF_BYCOMMAND, &mi);
160 RemoveMenu(hmenu, FCIDM_SHVIEW_EXPLORE + idCmdFirst, MF_BYCOMMAND);
162 mi.cbSize = sizeof(mi);
163 mi.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_STRING;
164 mi.dwTypeData = str;
165 mi.fState = MFS_ENABLED;
166 mi.wID = FCIDM_SHVIEW_EXPLORE;
167 mi.fType = MFT_STRING;
168 InsertMenuItemW(hmenu, (uFlags & CMF_EXPLORE) ? 1 : 2, MF_BYPOSITION, &mi);
171 SetMenuDefaultItem(hmenu, 0, MF_BYPOSITION);
173 if(uFlags & ~CMF_CANRENAME)
174 RemoveMenu(hmenu, FCIDM_SHVIEW_RENAME, MF_BYCOMMAND);
175 else
177 UINT enable = MF_BYCOMMAND;
179 /* can't rename more than one item at a time*/
180 if (!This->apidl || This->cidl > 1)
181 enable |= MFS_DISABLED;
182 else
184 DWORD attr = SFGAO_CANRENAME;
186 IShellFolder_GetAttributesOf(This->parent, 1, (LPCITEMIDLIST*)This->apidl, &attr);
187 enable |= (attr & SFGAO_CANRENAME) ? MFS_ENABLED : MFS_DISABLED;
190 EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, enable);
193 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, uIDMax-idCmdFirst);
195 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
198 /**************************************************************************
199 * DoOpenExplore
201 * for folders only
204 static void DoOpenExplore(ContextMenu *This, HWND hwnd, LPCSTR verb)
206 UINT i, bFolderFound = FALSE;
207 LPITEMIDLIST pidlFQ;
208 SHELLEXECUTEINFOA sei;
210 /* Find the first item in the list that is not a value. These commands
211 should never be invoked if there isn't at least one folder item in the list.*/
213 for(i = 0; i<This->cidl; i++)
215 if(!_ILIsValue(This->apidl[i]))
217 bFolderFound = TRUE;
218 break;
222 if (!bFolderFound) return;
224 pidlFQ = ILCombine(This->pidl, This->apidl[i]);
226 ZeroMemory(&sei, sizeof(sei));
227 sei.cbSize = sizeof(sei);
228 sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME;
229 sei.lpIDList = pidlFQ;
230 sei.lpClass = "Folder";
231 sei.hwnd = hwnd;
232 sei.nShow = SW_SHOWNORMAL;
233 sei.lpVerb = verb;
234 ShellExecuteExA(&sei);
235 SHFree(pidlFQ);
238 /**************************************************************************
239 * DoDelete
241 * deletes the currently selected items
243 static void DoDelete(ContextMenu *This)
245 ISFHelper *helper;
247 IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&helper);
248 if (helper)
250 ISFHelper_DeleteItems(helper, This->cidl, (LPCITEMIDLIST*)This->apidl);
251 ISFHelper_Release(helper);
255 /**************************************************************************
256 * DoCopyOrCut
258 * copies the currently selected items into the clipboard
260 static void DoCopyOrCut(ContextMenu *This, HWND hwnd, BOOL cut)
262 IDataObject *dataobject;
264 TRACE("(%p)->(wnd=%p, cut=%d)\n", This, hwnd, cut);
266 if (SUCCEEDED(IShellFolder_GetUIObjectOf(This->parent, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl, &IID_IDataObject, 0, (void**)&dataobject)))
268 OleSetClipboard(dataobject);
269 IDataObject_Release(dataobject);
273 /**************************************************************************
274 * Properties_AddPropSheetCallback
276 * Used by DoOpenProperties through SHCreatePropSheetExtArrayEx to add
277 * propertysheet pages from shell extensions.
279 static BOOL CALLBACK Properties_AddPropSheetCallback(HPROPSHEETPAGE hpage, LPARAM lparam)
281 LPPROPSHEETHEADERW psh = (LPPROPSHEETHEADERW) lparam;
282 psh->u3.phpage[psh->nPages++] = hpage;
284 return TRUE;
287 static void DoOpenProperties(ContextMenu *This, HWND hwnd)
289 static const UINT MAX_PROP_PAGES = 99;
290 static const WCHAR wszFolder[] = {'F','o','l','d','e','r', 0};
291 static const WCHAR wszFiletypeAll[] = {'*',0};
292 LPSHELLFOLDER lpDesktopSF;
293 LPSHELLFOLDER lpSF;
294 LPDATAOBJECT lpDo;
295 WCHAR wszFiletype[MAX_PATH];
296 WCHAR wszFilename[MAX_PATH];
297 PROPSHEETHEADERW psh;
298 HPROPSHEETPAGE hpages[MAX_PROP_PAGES];
299 HPSXA hpsxa;
300 UINT ret;
302 TRACE("(%p)->(wnd=%p)\n", This, hwnd);
304 ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
305 psh.dwSize = sizeof (PROPSHEETHEADERW);
306 psh.hwndParent = hwnd;
307 psh.dwFlags = PSH_PROPTITLE;
308 psh.nPages = 0;
309 psh.u3.phpage = hpages;
310 psh.u2.nStartPage = 0;
312 _ILSimpleGetTextW(This->apidl[0], (LPVOID)wszFilename, MAX_PATH);
313 psh.pszCaption = (LPCWSTR)wszFilename;
315 /* Find out where to look for the shell extensions */
316 if (_ILIsValue(This->apidl[0]))
318 char sTemp[64];
319 sTemp[0] = 0;
320 if (_ILGetExtension(This->apidl[0], sTemp, 64))
322 HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE);
323 MultiByteToWideChar(CP_ACP, 0, sTemp, -1, wszFiletype, MAX_PATH);
325 else
327 wszFiletype[0] = 0;
330 else if (_ILIsFolder(This->apidl[0]))
332 lstrcpynW(wszFiletype, wszFolder, 64);
334 else if (_ILIsSpecialFolder(This->apidl[0]))
336 LPGUID folderGUID;
337 static const WCHAR wszclsid[] = {'C','L','S','I','D','\\', 0};
338 folderGUID = _ILGetGUIDPointer(This->apidl[0]);
339 lstrcpyW(wszFiletype, wszclsid);
340 StringFromGUID2(folderGUID, &wszFiletype[6], MAX_PATH - 6);
342 else
344 FIXME("Requested properties for unknown type.\n");
345 return;
348 /* Get a suitable DataObject for accessing the files */
349 SHGetDesktopFolder(&lpDesktopSF);
350 if (_ILIsPidlSimple(This->pidl))
352 ret = IShellFolder_GetUIObjectOf(lpDesktopSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl,
353 &IID_IDataObject, NULL, (LPVOID *)&lpDo);
354 IShellFolder_Release(lpDesktopSF);
356 else
358 IShellFolder_BindToObject(lpDesktopSF, This->pidl, NULL, &IID_IShellFolder, (LPVOID*) &lpSF);
359 ret = IShellFolder_GetUIObjectOf(lpSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl,
360 &IID_IDataObject, NULL, (LPVOID *)&lpDo);
361 IShellFolder_Release(lpSF);
362 IShellFolder_Release(lpDesktopSF);
365 if (SUCCEEDED(ret))
367 hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletype, MAX_PROP_PAGES - psh.nPages, lpDo);
368 if (hpsxa != NULL)
370 SHAddFromPropSheetExtArray(hpsxa, Properties_AddPropSheetCallback, (LPARAM)&psh);
371 SHDestroyPropSheetExtArray(hpsxa);
373 hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletypeAll, MAX_PROP_PAGES - psh.nPages, lpDo);
374 if (hpsxa != NULL)
376 SHAddFromPropSheetExtArray(hpsxa, Properties_AddPropSheetCallback, (LPARAM)&psh);
377 SHDestroyPropSheetExtArray(hpsxa);
379 IDataObject_Release(lpDo);
382 if (psh.nPages)
383 PropertySheetW(&psh);
384 else
385 FIXME("No property pages found.\n");
388 static HRESULT WINAPI ItemMenu_InvokeCommand(
389 IContextMenu3 *iface,
390 LPCMINVOKECOMMANDINFO lpcmi)
392 ContextMenu *This = impl_from_IContextMenu3(iface);
394 if (lpcmi->cbSize != sizeof(CMINVOKECOMMANDINFO))
395 FIXME("Is an EX structure\n");
397 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);
399 if( HIWORD(lpcmi->lpVerb)==0 && LOWORD(lpcmi->lpVerb) > FCIDM_SHVIEWLAST)
401 TRACE("Invalid Verb %x\n",LOWORD(lpcmi->lpVerb));
402 return E_INVALIDARG;
405 if (HIWORD(lpcmi->lpVerb) == 0)
407 switch(LOWORD(lpcmi->lpVerb))
409 case FCIDM_SHVIEW_EXPLORE:
410 TRACE("Verb FCIDM_SHVIEW_EXPLORE\n");
411 DoOpenExplore(This, lpcmi->hwnd, "explore");
412 break;
413 case FCIDM_SHVIEW_OPEN:
414 TRACE("Verb FCIDM_SHVIEW_OPEN\n");
415 DoOpenExplore(This, lpcmi->hwnd, "open");
416 break;
417 case FCIDM_SHVIEW_RENAME:
419 IShellBrowser *browser;
421 /* get the active IShellView */
422 browser = (IShellBrowser*)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
423 if (browser)
425 IShellView *view;
427 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(browser, &view)))
429 TRACE("(shellview=%p)\n", view);
430 IShellView_SelectItem(view, This->apidl[0],
431 SVSI_DESELECTOTHERS|SVSI_EDIT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_SELECT);
432 IShellView_Release(view);
435 break;
437 case FCIDM_SHVIEW_DELETE:
438 TRACE("Verb FCIDM_SHVIEW_DELETE\n");
439 DoDelete(This);
440 break;
441 case FCIDM_SHVIEW_COPY:
442 TRACE("Verb FCIDM_SHVIEW_COPY\n");
443 DoCopyOrCut(This, lpcmi->hwnd, FALSE);
444 break;
445 case FCIDM_SHVIEW_CUT:
446 TRACE("Verb FCIDM_SHVIEW_CUT\n");
447 DoCopyOrCut(This, lpcmi->hwnd, TRUE);
448 break;
449 case FCIDM_SHVIEW_PROPERTIES:
450 TRACE("Verb FCIDM_SHVIEW_PROPERTIES\n");
451 DoOpenProperties(This, lpcmi->hwnd);
452 break;
453 default:
454 FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb));
455 return E_INVALIDARG;
458 else
460 TRACE("Verb is %s\n",debugstr_a(lpcmi->lpVerb));
461 if (strcmp(lpcmi->lpVerb,"delete")==0)
462 DoDelete(This);
463 else if (strcmp(lpcmi->lpVerb,"properties")==0)
464 DoOpenProperties(This, lpcmi->hwnd);
465 else {
466 FIXME("Unhandled string verb %s\n",debugstr_a(lpcmi->lpVerb));
467 return E_FAIL;
470 return S_OK;
473 static HRESULT WINAPI ItemMenu_GetCommandString(
474 IContextMenu3 *iface,
475 UINT_PTR idCommand,
476 UINT uFlags,
477 UINT* lpReserved,
478 LPSTR lpszName,
479 UINT uMaxNameLen)
481 ContextMenu *This = impl_from_IContextMenu3(iface);
482 HRESULT hr = E_INVALIDARG;
484 TRACE("(%p)->(%lx flags=%x %p name=%p len=%x)\n", This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
486 switch(uFlags)
488 case GCS_HELPTEXTA:
489 case GCS_HELPTEXTW:
490 hr = E_NOTIMPL;
491 break;
493 case GCS_VERBA:
494 switch(idCommand)
496 case FCIDM_SHVIEW_OPEN:
497 strcpy(lpszName, "open");
498 hr = S_OK;
499 break;
500 case FCIDM_SHVIEW_EXPLORE:
501 strcpy(lpszName, "explore");
502 hr = S_OK;
503 break;
504 case FCIDM_SHVIEW_CUT:
505 strcpy(lpszName, "cut");
506 hr = S_OK;
507 break;
508 case FCIDM_SHVIEW_COPY:
509 strcpy(lpszName, "copy");
510 hr = S_OK;
511 break;
512 case FCIDM_SHVIEW_CREATELINK:
513 strcpy(lpszName, "link");
514 hr = S_OK;
515 break;
516 case FCIDM_SHVIEW_DELETE:
517 strcpy(lpszName, "delete");
518 hr = S_OK;
519 break;
520 case FCIDM_SHVIEW_PROPERTIES:
521 strcpy(lpszName, "properties");
522 hr = S_OK;
523 break;
524 case FCIDM_SHVIEW_RENAME:
525 strcpy(lpszName, "rename");
526 hr = S_OK;
527 break;
529 break;
531 /* NT 4.0 with IE 3.0x or no IE will always call This with GCS_VERBW. In This
532 case, you need to do the lstrcpyW to the pointer passed.*/
533 case GCS_VERBW:
534 switch(idCommand)
536 case FCIDM_SHVIEW_OPEN:
537 MultiByteToWideChar(CP_ACP, 0, "open", -1, (LPWSTR)lpszName, uMaxNameLen);
538 hr = S_OK;
539 break;
540 case FCIDM_SHVIEW_EXPLORE:
541 MultiByteToWideChar(CP_ACP, 0, "explore", -1, (LPWSTR)lpszName, uMaxNameLen);
542 hr = S_OK;
543 break;
544 case FCIDM_SHVIEW_CUT:
545 MultiByteToWideChar(CP_ACP, 0, "cut", -1, (LPWSTR)lpszName, uMaxNameLen);
546 hr = S_OK;
547 break;
548 case FCIDM_SHVIEW_COPY:
549 MultiByteToWideChar(CP_ACP, 0, "copy", -1, (LPWSTR)lpszName, uMaxNameLen);
550 hr = S_OK;
551 break;
552 case FCIDM_SHVIEW_CREATELINK:
553 MultiByteToWideChar(CP_ACP, 0, "link", -1, (LPWSTR)lpszName, uMaxNameLen);
554 hr = S_OK;
555 break;
556 case FCIDM_SHVIEW_DELETE:
557 MultiByteToWideChar(CP_ACP, 0, "delete", -1, (LPWSTR)lpszName, uMaxNameLen);
558 hr = S_OK;
559 break;
560 case FCIDM_SHVIEW_PROPERTIES:
561 MultiByteToWideChar(CP_ACP, 0, "properties", -1, (LPWSTR)lpszName, uMaxNameLen);
562 hr = S_OK;
563 break;
564 case FCIDM_SHVIEW_RENAME:
565 MultiByteToWideChar( CP_ACP, 0, "rename", -1, (LPWSTR)lpszName, uMaxNameLen );
566 hr = S_OK;
567 break;
569 break;
571 case GCS_VALIDATEA:
572 case GCS_VALIDATEW:
573 hr = S_OK;
574 break;
576 TRACE("-- (%p)->(name=%s)\n", This, lpszName);
577 return hr;
580 /**************************************************************************
581 * NOTES
582 * should be only in IContextMenu2 and IContextMenu3
583 * is nevertheless called from word95
585 static HRESULT WINAPI ContextMenu_HandleMenuMsg(IContextMenu3 *iface, UINT msg,
586 WPARAM wParam, LPARAM lParam)
588 ContextMenu *This = impl_from_IContextMenu3(iface);
589 FIXME("(%p)->(0x%x 0x%lx 0x%lx): stub\n", This, msg, wParam, lParam);
590 return E_NOTIMPL;
593 static HRESULT WINAPI ContextMenu_HandleMenuMsg2(IContextMenu3 *iface, UINT msg,
594 WPARAM wParam, LPARAM lParam, LRESULT *result)
596 ContextMenu *This = impl_from_IContextMenu3(iface);
597 FIXME("(%p)->(0x%x 0x%lx 0x%lx %p): stub\n", This, msg, wParam, lParam, result);
598 return E_NOTIMPL;
601 static const IContextMenu3Vtbl ItemContextMenuVtbl =
603 ContextMenu_QueryInterface,
604 ContextMenu_AddRef,
605 ContextMenu_Release,
606 ItemMenu_QueryContextMenu,
607 ItemMenu_InvokeCommand,
608 ItemMenu_GetCommandString,
609 ContextMenu_HandleMenuMsg,
610 ContextMenu_HandleMenuMsg2
613 HRESULT ItemMenu_Constructor(IShellFolder *parent, LPCITEMIDLIST pidl, const LPCITEMIDLIST *apidl, UINT cidl,
614 REFIID riid, void **pObj)
616 ContextMenu* This;
617 HRESULT hr;
618 UINT i;
620 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
621 if (!This) return E_OUTOFMEMORY;
623 This->IContextMenu3_iface.lpVtbl = &ItemContextMenuVtbl;
624 This->ref = 1;
625 This->parent = parent;
626 if (parent) IShellFolder_AddRef(parent);
628 This->pidl = ILClone(pidl);
629 This->apidl = _ILCopyaPidl(apidl, cidl);
630 This->cidl = cidl;
631 This->allvalues = TRUE;
633 This->desktop = FALSE;
635 for (i = 0; i < cidl; i++)
636 This->allvalues &= (_ILIsValue(apidl[i]) ? 1 : 0);
638 hr = IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, pObj);
639 IContextMenu3_Release(&This->IContextMenu3_iface);
641 return hr;
644 /* Background menu implementation */
645 static HRESULT WINAPI BackgroundMenu_QueryContextMenu(
646 IContextMenu3 *iface,
647 HMENU hMenu,
648 UINT indexMenu,
649 UINT idCmdFirst,
650 UINT idCmdLast,
651 UINT uFlags)
653 ContextMenu *This = impl_from_IContextMenu3(iface);
654 HMENU hMyMenu;
655 UINT idMax;
656 HRESULT hr;
658 TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",
659 This, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
661 hMyMenu = LoadMenuA(shell32_hInstance, "MENU_002");
662 if (uFlags & CMF_DEFAULTONLY)
664 HMENU ourMenu = GetSubMenu(hMyMenu,0);
665 UINT oldDef = GetMenuDefaultItem(hMenu,TRUE,GMDI_USEDISABLED);
666 UINT newDef = GetMenuDefaultItem(ourMenu,TRUE,GMDI_USEDISABLED);
667 if (newDef != oldDef)
668 SetMenuDefaultItem(hMenu,newDef,TRUE);
669 if (newDef!=0xFFFFFFFF)
670 hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, newDef+1);
671 else
672 hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
674 else
676 idMax = Shell_MergeMenus (hMenu, GetSubMenu(hMyMenu,0), indexMenu,
677 idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS);
678 hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, idMax-idCmdFirst);
680 DestroyMenu(hMyMenu);
682 TRACE("(%p)->returning 0x%x\n",This,hr);
683 return hr;
686 static void DoNewFolder(ContextMenu *This, IShellView *view)
688 ISFHelper *helper;
690 IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&helper);
691 if (helper)
693 WCHAR nameW[MAX_PATH];
694 LPITEMIDLIST pidl;
696 ISFHelper_GetUniqueName(helper, nameW, MAX_PATH);
697 ISFHelper_AddFolder(helper, 0, nameW, &pidl);
699 if (view)
701 /* if we are in a shellview do labeledit */
702 IShellView_SelectItem(view,
703 pidl,(SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE
704 |SVSI_FOCUSED|SVSI_SELECT));
707 SHFree(pidl);
708 ISFHelper_Release(helper);
712 static BOOL DoPaste(ContextMenu *This)
714 BOOL bSuccess = FALSE;
715 IDataObject * pda;
717 TRACE("\n");
719 if(SUCCEEDED(OleGetClipboard(&pda)))
721 STGMEDIUM medium;
722 FORMATETC formatetc;
724 TRACE("pda=%p\n", pda);
726 /* Set the FORMATETC structure*/
727 InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLISTW), TYMED_HGLOBAL);
729 /* Get the pidls from IDataObject */
730 if(SUCCEEDED(IDataObject_GetData(pda,&formatetc,&medium)))
732 LPITEMIDLIST * apidl;
733 LPITEMIDLIST pidl;
734 IShellFolder *psfFrom = NULL, *psfDesktop;
736 LPIDA lpcida = GlobalLock(medium.u.hGlobal);
737 TRACE("cida=%p\n", lpcida);
739 apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
741 /* bind to the source shellfolder */
742 SHGetDesktopFolder(&psfDesktop);
743 if(psfDesktop)
745 IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (LPVOID*)&psfFrom);
746 IShellFolder_Release(psfDesktop);
749 if (psfFrom)
751 /* get source and destination shellfolder */
752 ISFHelper *psfhlpdst, *psfhlpsrc;
753 IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&psfhlpdst);
754 IShellFolder_QueryInterface(psfFrom, &IID_ISFHelper, (void**)&psfhlpsrc);
756 /* do the copy/move */
757 if (psfhlpdst && psfhlpsrc)
759 ISFHelper_CopyItems(psfhlpdst, psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl);
760 /* FIXME handle move
761 ISFHelper_DeleteItems(psfhlpsrc, lpcida->cidl, apidl);
764 if(psfhlpdst) ISFHelper_Release(psfhlpdst);
765 if(psfhlpsrc) ISFHelper_Release(psfhlpsrc);
766 IShellFolder_Release(psfFrom);
769 _ILFreeaPidl(apidl, lpcida->cidl);
770 SHFree(pidl);
772 /* release the medium*/
773 ReleaseStgMedium(&medium);
775 IDataObject_Release(pda);
777 #if 0
778 HGLOBAL hMem;
780 OpenClipboard(NULL);
781 hMem = GetClipboardData(CF_HDROP);
783 if(hMem)
785 char * pDropFiles = GlobalLock(hMem);
786 if(pDropFiles)
788 int len, offset = sizeof(DROPFILESTRUCT);
790 while( pDropFiles[offset] != 0)
792 len = strlen(pDropFiles + offset);
793 TRACE("%s\n", pDropFiles + offset);
794 offset += len+1;
797 GlobalUnlock(hMem);
799 CloseClipboard();
800 #endif
801 return bSuccess;
804 static HRESULT WINAPI BackgroundMenu_InvokeCommand(
805 IContextMenu3 *iface,
806 LPCMINVOKECOMMANDINFO lpcmi)
808 ContextMenu *This = impl_from_IContextMenu3(iface);
809 IShellBrowser *browser;
810 IShellView *view = NULL;
811 HWND hWnd = NULL;
813 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", This, lpcmi, lpcmi->lpVerb, lpcmi->hwnd);
815 /* get the active IShellView */
816 if ((browser = (IShellBrowser*)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0)))
818 if (SUCCEEDED(IShellBrowser_QueryActiveShellView(browser, &view)))
819 IShellView_GetWindow(view, &hWnd);
822 if(HIWORD(lpcmi->lpVerb))
824 TRACE("%s\n", debugstr_a(lpcmi->lpVerb));
826 if (!strcmp(lpcmi->lpVerb, CMDSTR_NEWFOLDERA))
828 DoNewFolder(This, view);
830 else if (!strcmp(lpcmi->lpVerb, CMDSTR_VIEWLISTA))
832 if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_LISTVIEW, 0), 0);
834 else if (!strcmp(lpcmi->lpVerb, CMDSTR_VIEWDETAILSA))
836 if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_REPORTVIEW, 0), 0);
838 else
840 FIXME("please report: unknown verb %s\n", debugstr_a(lpcmi->lpVerb));
843 else
845 switch (LOWORD(lpcmi->lpVerb))
847 case FCIDM_SHVIEW_REFRESH:
848 if (view) IShellView_Refresh(view);
849 break;
851 case FCIDM_SHVIEW_NEWFOLDER:
852 DoNewFolder(This, view);
853 break;
855 case FCIDM_SHVIEW_INSERT:
856 DoPaste(This);
857 break;
859 case FCIDM_SHVIEW_PROPERTIES:
860 if (This->desktop) {
861 ShellExecuteA(lpcmi->hwnd, "open", "rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL);
862 } else {
863 FIXME("launch item properties dialog\n");
865 break;
867 default:
868 /* if it's an id just pass it to the parent shv */
869 if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0);
870 break;
874 if (view)
875 IShellView_Release(view);
877 return S_OK;
880 static HRESULT WINAPI BackgroundMenu_GetCommandString(
881 IContextMenu3 *iface,
882 UINT_PTR idCommand,
883 UINT uFlags,
884 UINT* lpReserved,
885 LPSTR lpszName,
886 UINT uMaxNameLen)
888 ContextMenu *This = impl_from_IContextMenu3(iface);
890 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
892 /* test the existence of the menu items, the file dialog enables
893 the buttons according to this */
894 if (uFlags == GCS_VALIDATEA)
896 if(HIWORD(idCommand))
898 if (!strcmp((LPSTR)idCommand, CMDSTR_VIEWLISTA) ||
899 !strcmp((LPSTR)idCommand, CMDSTR_VIEWDETAILSA) ||
900 !strcmp((LPSTR)idCommand, CMDSTR_NEWFOLDERA))
902 return S_OK;
907 FIXME("unknown command string\n");
908 return E_FAIL;
911 static const IContextMenu3Vtbl BackgroundContextMenuVtbl =
913 ContextMenu_QueryInterface,
914 ContextMenu_AddRef,
915 ContextMenu_Release,
916 BackgroundMenu_QueryContextMenu,
917 BackgroundMenu_InvokeCommand,
918 BackgroundMenu_GetCommandString,
919 ContextMenu_HandleMenuMsg,
920 ContextMenu_HandleMenuMsg2
923 HRESULT BackgroundMenu_Constructor(IShellFolder *parent, BOOL desktop, REFIID riid, void **pObj)
925 ContextMenu *This;
926 HRESULT hr;
928 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
929 if (!This) return E_OUTOFMEMORY;
931 This->IContextMenu3_iface.lpVtbl = &BackgroundContextMenuVtbl;
932 This->ref = 1;
933 This->parent = parent;
935 This->pidl = NULL;
936 This->apidl = NULL;
937 This->cidl = 0;
938 This->allvalues = FALSE;
940 This->desktop = desktop;
941 if (parent) IShellFolder_AddRef(parent);
943 hr = IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, pObj);
944 IContextMenu3_Release(&This->IContextMenu3_iface);
946 return hr;