netstat: Initial implementation.
[wine] / dlls / shell32 / shlview_cmenu.c
1 /*
2  *      IContextMenu for items in the shellview
3  *
4  * Copyright 1998-2000 Juergen Schmied <juergen.schmied@debitel.net>,
5  *                                     <juergen.schmied@metronet.de>
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include <string.h>
23
24 #define COBJMACROS
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27
28 #include "winerror.h"
29 #include "wine/debug.h"
30
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"
38
39 #include "shell32_main.h"
40 #include "shellfolder.h"
41
42 #include "shresdef.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(shell);
45
46 typedef struct
47 {
48     IContextMenu3 IContextMenu3_iface;
49     LONG ref;
50
51     IShellFolder* parent;
52     UINT verb_offset;
53
54     /* item menu data */
55     LPITEMIDLIST  pidl;  /* root pidl */
56     LPITEMIDLIST *apidl; /* array of child pidls */
57     UINT cidl;
58     BOOL allvalues;
59
60     /* background menu data */
61     BOOL desktop;
62 } ContextMenu;
63
64 static inline ContextMenu *impl_from_IContextMenu3(IContextMenu3 *iface)
65 {
66     return CONTAINING_RECORD(iface, ContextMenu, IContextMenu3_iface);
67 }
68
69 static HRESULT WINAPI ContextMenu_QueryInterface(IContextMenu3 *iface, REFIID riid, LPVOID *ppvObj)
70 {
71     ContextMenu *This = impl_from_IContextMenu3(iface);
72
73     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObj);
74
75     *ppvObj = NULL;
76
77     if (IsEqualIID(riid, &IID_IUnknown)      ||
78         IsEqualIID(riid, &IID_IContextMenu)  ||
79         IsEqualIID(riid, &IID_IContextMenu2) ||
80         IsEqualIID(riid, &IID_IContextMenu3))
81     {
82         *ppvObj = This;
83     }
84     else if (IsEqualIID(riid, &IID_IShellExtInit))  /*IShellExtInit*/
85     {
86         FIXME("-- LPSHELLEXTINIT pointer requested\n");
87     }
88
89     if(*ppvObj)
90     {
91         IContextMenu3_AddRef(iface);
92         return S_OK;
93     }
94
95     TRACE("-- Interface: E_NOINTERFACE\n");
96     return E_NOINTERFACE;
97 }
98
99 static ULONG WINAPI ContextMenu_AddRef(IContextMenu3 *iface)
100 {
101     ContextMenu *This = impl_from_IContextMenu3(iface);
102     ULONG ref = InterlockedIncrement(&This->ref);
103     TRACE("(%p)->(%u)\n", This, ref);
104     return ref;
105 }
106
107 static ULONG WINAPI ContextMenu_Release(IContextMenu3 *iface)
108 {
109     ContextMenu *This = impl_from_IContextMenu3(iface);
110     ULONG ref = InterlockedDecrement(&This->ref);
111
112     TRACE("(%p)->(%u)\n", This, ref);
113
114     if (!ref)
115     {
116         if(This->parent)
117             IShellFolder_Release(This->parent);
118
119         SHFree(This->pidl);
120         _ILFreeaPidl(This->apidl, This->cidl);
121
122         HeapFree(GetProcessHeap(), 0, This);
123     }
124
125     return ref;
126 }
127
128 static HRESULT WINAPI ItemMenu_QueryContextMenu(
129         IContextMenu3 *iface,
130         HMENU hmenu,
131         UINT indexMenu,
132         UINT idCmdFirst,
133         UINT idCmdLast,
134         UINT uFlags)
135 {
136     ContextMenu *This = impl_from_IContextMenu3(iface);
137     INT uIDMax;
138
139     TRACE("(%p)->(%p %d 0x%x 0x%x 0x%x )\n", This, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
140
141     This->verb_offset = idCmdFirst;
142
143     if(!(CMF_DEFAULTONLY & uFlags) && This->cidl > 0)
144     {
145         HMENU hmenures = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(MENU_SHV_FILE));
146
147         if(uFlags & CMF_EXPLORE)
148             RemoveMenu(hmenures, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
149
150         uIDMax = Shell_MergeMenus(hmenu, GetSubMenu(hmenures, 0), indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS);
151
152         DestroyMenu(hmenures);
153
154         if(This->allvalues)
155         {
156             MENUITEMINFOW mi;
157             WCHAR str[255];
158             mi.cbSize = sizeof(mi);
159             mi.fMask = MIIM_ID | MIIM_STRING | MIIM_FTYPE;
160             mi.dwTypeData = str;
161             mi.cch = 255;
162             GetMenuItemInfoW(hmenu, FCIDM_SHVIEW_EXPLORE, MF_BYCOMMAND, &mi);
163             RemoveMenu(hmenu, FCIDM_SHVIEW_EXPLORE, MF_BYCOMMAND);
164
165             mi.cbSize = sizeof(mi);
166             mi.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
167             mi.dwTypeData = str;
168             mi.fState = MFS_ENABLED;
169             mi.wID = FCIDM_SHVIEW_EXPLORE;
170             mi.fType = MFT_STRING;
171             InsertMenuItemW(hmenu, (uFlags & CMF_EXPLORE) ? 1 : 2, MF_BYPOSITION, &mi);
172         }
173
174         SetMenuDefaultItem(hmenu, 0, MF_BYPOSITION);
175
176         if(uFlags & ~CMF_CANRENAME)
177             RemoveMenu(hmenu, FCIDM_SHVIEW_RENAME, MF_BYCOMMAND);
178         else
179         {
180             UINT enable = MF_BYCOMMAND;
181
182             /* can't rename more than one item at a time*/
183             if (!This->apidl || This->cidl > 1)
184                 enable |= MFS_DISABLED;
185             else
186             {
187                 DWORD attr = SFGAO_CANRENAME;
188
189                 IShellFolder_GetAttributesOf(This->parent, 1, (LPCITEMIDLIST*)This->apidl, &attr);
190                 enable |= (attr & SFGAO_CANRENAME) ? MFS_ENABLED : MFS_DISABLED;
191             }
192
193             EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, enable);
194         }
195
196         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, uIDMax-idCmdFirst);
197     }
198     return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
199 }
200
201 /**************************************************************************
202 * DoOpenExplore
203 *
204 *  for folders only
205 */
206
207 static void DoOpenExplore(ContextMenu *This, HWND hwnd, LPCSTR verb)
208 {
209         UINT i, bFolderFound = FALSE;
210         LPITEMIDLIST    pidlFQ;
211         SHELLEXECUTEINFOA       sei;
212
213         /* Find the first item in the list that is not a value. These commands
214             should never be invoked if there isn't at least one folder item in the list.*/
215
216         for(i = 0; i<This->cidl; i++)
217         {
218           if(!_ILIsValue(This->apidl[i]))
219           {
220             bFolderFound = TRUE;
221             break;
222           }
223         }
224
225         if (!bFolderFound) return;
226
227         pidlFQ = ILCombine(This->pidl, This->apidl[i]);
228
229         ZeroMemory(&sei, sizeof(sei));
230         sei.cbSize = sizeof(sei);
231         sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME;
232         sei.lpIDList = pidlFQ;
233         sei.lpClass = "Folder";
234         sei.hwnd = hwnd;
235         sei.nShow = SW_SHOWNORMAL;
236         sei.lpVerb = verb;
237         ShellExecuteExA(&sei);
238         SHFree(pidlFQ);
239 }
240
241 /**************************************************************************
242  * DoDelete
243  *
244  * deletes the currently selected items
245  */
246 static void DoDelete(ContextMenu *This)
247 {
248     ISFHelper *helper;
249
250     IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&helper);
251     if (helper)
252     {
253         ISFHelper_DeleteItems(helper, This->cidl, (LPCITEMIDLIST*)This->apidl);
254         ISFHelper_Release(helper);
255     }
256 }
257
258 /**************************************************************************
259  * DoCopyOrCut
260  *
261  * copies the currently selected items into the clipboard
262  */
263 static BOOL DoCopyOrCut(ContextMenu *This, HWND hwnd, BOOL cut)
264 {
265     IDataObject *dataobject;
266     IShellBrowser *browser;
267     IShellView *view;
268
269     TRACE("(%p)->(wnd=%p, cut=%d)\n", This, hwnd, cut);
270
271     /* get the active IShellView */
272     if ((browser = (IShellBrowser*)SendMessageA(hwnd, CWM_GETISHELLBROWSER, 0, 0)))
273     {
274         if (SUCCEEDED(IShellBrowser_QueryActiveShellView(browser, &view)))
275         {
276             if (SUCCEEDED(IShellView_GetItemObject(view, SVGIO_SELECTION, &IID_IDataObject, (void**)&dataobject)))
277             {
278                 OleSetClipboard(dataobject);
279                 IDataObject_Release(dataobject);
280             }
281             IShellView_Release(view);
282         }
283     }
284
285     return TRUE;
286 }
287
288 /**************************************************************************
289  * Properties_AddPropSheetCallback
290  *
291  * Used by DoOpenProperties through SHCreatePropSheetExtArrayEx to add
292  * propertysheet pages from shell extensions.
293  */
294 static BOOL CALLBACK Properties_AddPropSheetCallback(HPROPSHEETPAGE hpage, LPARAM lparam)
295 {
296         LPPROPSHEETHEADERW psh = (LPPROPSHEETHEADERW) lparam;
297         psh->u3.phpage[psh->nPages++] = hpage;
298
299         return TRUE;
300 }
301
302 static void DoOpenProperties(ContextMenu *This, HWND hwnd)
303 {
304         static const UINT MAX_PROP_PAGES = 99;
305         static const WCHAR wszFolder[] = {'F','o','l','d','e','r', 0};
306         static const WCHAR wszFiletypeAll[] = {'*',0};
307         LPSHELLFOLDER lpDesktopSF;
308         LPSHELLFOLDER lpSF;
309         LPDATAOBJECT lpDo;
310         WCHAR wszFiletype[MAX_PATH];
311         WCHAR wszFilename[MAX_PATH];
312         PROPSHEETHEADERW psh;
313         HPROPSHEETPAGE hpages[MAX_PROP_PAGES];
314         HPSXA hpsxa;
315         UINT ret;
316
317         TRACE("(%p)->(wnd=%p)\n", This, hwnd);
318
319         ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
320         psh.dwSize = sizeof (PROPSHEETHEADERW);
321         psh.hwndParent = hwnd;
322         psh.dwFlags = PSH_PROPTITLE;
323         psh.nPages = 0;
324         psh.u3.phpage = hpages;
325         psh.u2.nStartPage = 0;
326
327         _ILSimpleGetTextW(This->apidl[0], (LPVOID)wszFilename, MAX_PATH);
328         psh.pszCaption = (LPCWSTR)wszFilename;
329
330         /* Find out where to look for the shell extensions */
331         if (_ILIsValue(This->apidl[0]))
332         {
333             char sTemp[64];
334             sTemp[0] = 0;
335             if (_ILGetExtension(This->apidl[0], sTemp, 64))
336             {
337                 HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE);
338                 MultiByteToWideChar(CP_ACP, 0, sTemp, -1, wszFiletype, MAX_PATH);
339             }
340             else
341             {
342                 wszFiletype[0] = 0;
343             }
344         }
345         else if (_ILIsFolder(This->apidl[0]))
346         {
347             lstrcpynW(wszFiletype, wszFolder, 64);
348         }
349         else if (_ILIsSpecialFolder(This->apidl[0]))
350         {
351             LPGUID folderGUID;
352             static const WCHAR wszclsid[] = {'C','L','S','I','D','\\', 0};
353             folderGUID = _ILGetGUIDPointer(This->apidl[0]);
354             lstrcpyW(wszFiletype, wszclsid);
355             StringFromGUID2(folderGUID, &wszFiletype[6], MAX_PATH - 6);
356         }
357         else
358         {
359             FIXME("Requested properties for unknown type.\n");
360             return;
361         }
362
363         /* Get a suitable DataObject for accessing the files */
364         SHGetDesktopFolder(&lpDesktopSF);
365         if (_ILIsPidlSimple(This->pidl))
366         {
367             ret = IShellFolder_GetUIObjectOf(lpDesktopSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl,
368                                              &IID_IDataObject, NULL, (LPVOID *)&lpDo);
369             IShellFolder_Release(lpDesktopSF);
370         }
371         else
372         {
373             IShellFolder_BindToObject(lpDesktopSF, This->pidl, NULL, &IID_IShellFolder, (LPVOID*) &lpSF);
374             ret = IShellFolder_GetUIObjectOf(lpSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl,
375                                              &IID_IDataObject, NULL, (LPVOID *)&lpDo);
376             IShellFolder_Release(lpSF);
377             IShellFolder_Release(lpDesktopSF);
378         }
379
380         if (SUCCEEDED(ret))
381         {
382             hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletype, MAX_PROP_PAGES - psh.nPages, lpDo);
383             if (hpsxa != NULL)
384             {
385                 SHAddFromPropSheetExtArray(hpsxa, Properties_AddPropSheetCallback, (LPARAM)&psh);
386                 SHDestroyPropSheetExtArray(hpsxa);
387             }
388             hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletypeAll, MAX_PROP_PAGES - psh.nPages, lpDo);
389             if (hpsxa != NULL)
390             {
391                 SHAddFromPropSheetExtArray(hpsxa, Properties_AddPropSheetCallback, (LPARAM)&psh);
392                 SHDestroyPropSheetExtArray(hpsxa);
393             }
394             IDataObject_Release(lpDo);
395         }
396
397         if (psh.nPages)
398             PropertySheetW(&psh);
399         else
400             FIXME("No property pages found.\n");
401 }
402
403 static HRESULT WINAPI ItemMenu_InvokeCommand(
404         IContextMenu3 *iface,
405         LPCMINVOKECOMMANDINFO lpcmi)
406 {
407     ContextMenu *This = impl_from_IContextMenu3(iface);
408
409     if (lpcmi->cbSize != sizeof(CMINVOKECOMMANDINFO))
410         FIXME("Is an EX structure\n");
411
412     TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);
413
414     if( HIWORD(lpcmi->lpVerb)==0 && LOWORD(lpcmi->lpVerb) > FCIDM_SHVIEWLAST)
415     {
416         TRACE("Invalid Verb %x\n",LOWORD(lpcmi->lpVerb));
417         return E_INVALIDARG;
418     }
419
420     if (HIWORD(lpcmi->lpVerb) == 0)
421     {
422         switch(LOWORD(lpcmi->lpVerb - This->verb_offset))
423         {
424         case FCIDM_SHVIEW_EXPLORE:
425             TRACE("Verb FCIDM_SHVIEW_EXPLORE\n");
426             DoOpenExplore(This, lpcmi->hwnd, "explore");
427             break;
428         case FCIDM_SHVIEW_OPEN:
429             TRACE("Verb FCIDM_SHVIEW_OPEN\n");
430             DoOpenExplore(This, lpcmi->hwnd, "open");
431             break;
432         case FCIDM_SHVIEW_RENAME:
433         {
434             IShellBrowser *browser;
435
436             /* get the active IShellView */
437             browser = (IShellBrowser*)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
438             if (browser)
439             {
440                 IShellView *view;
441
442                 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(browser, &view)))
443                 {
444                     TRACE("(shellview=%p)\n", view);
445                     IShellView_SelectItem(view, This->apidl[0],
446                          SVSI_DESELECTOTHERS|SVSI_EDIT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_SELECT);
447                     IShellView_Release(view);
448                 }
449             }
450             break;
451         }
452         case FCIDM_SHVIEW_DELETE:
453             TRACE("Verb FCIDM_SHVIEW_DELETE\n");
454             DoDelete(This);
455             break;
456         case FCIDM_SHVIEW_COPY:
457             TRACE("Verb FCIDM_SHVIEW_COPY\n");
458             DoCopyOrCut(This, lpcmi->hwnd, FALSE);
459             break;
460         case FCIDM_SHVIEW_CUT:
461             TRACE("Verb FCIDM_SHVIEW_CUT\n");
462             DoCopyOrCut(This, lpcmi->hwnd, TRUE);
463             break;
464         case FCIDM_SHVIEW_PROPERTIES:
465             TRACE("Verb FCIDM_SHVIEW_PROPERTIES\n");
466             DoOpenProperties(This, lpcmi->hwnd);
467             break;
468         default:
469             FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb)-This->verb_offset);
470             return E_INVALIDARG;
471         }
472     }
473     else
474     {
475         TRACE("Verb is %s\n",debugstr_a(lpcmi->lpVerb));
476         if (strcmp(lpcmi->lpVerb,"delete")==0)
477             DoDelete(This);
478         else if (strcmp(lpcmi->lpVerb,"properties")==0)
479             DoOpenProperties(This, lpcmi->hwnd);
480         else {
481             FIXME("Unhandled string verb %s\n",debugstr_a(lpcmi->lpVerb));
482             return E_FAIL;
483         }
484     }
485     return S_OK;
486 }
487
488 static HRESULT WINAPI ItemMenu_GetCommandString(
489         IContextMenu3 *iface,
490         UINT_PTR idCommand,
491         UINT uFlags,
492         UINT* lpReserved,
493         LPSTR lpszName,
494         UINT uMaxNameLen)
495 {
496         ContextMenu *This = impl_from_IContextMenu3(iface);
497         HRESULT hr = E_INVALIDARG;
498
499         TRACE("(%p)->(%lx flags=%x %p name=%p len=%x)\n", This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
500
501         switch(uFlags)
502         {
503           case GCS_HELPTEXTA:
504           case GCS_HELPTEXTW:
505             hr = E_NOTIMPL;
506             break;
507
508           case GCS_VERBA:
509             switch(idCommand-This->verb_offset)
510             {
511             case FCIDM_SHVIEW_RENAME:
512                 strcpy(lpszName, "rename");
513                 hr = S_OK;
514                 break;
515             }
516             break;
517
518              /* NT 4.0 with IE 3.0x or no IE will always call This with GCS_VERBW. In This
519              case, you need to do the lstrcpyW to the pointer passed.*/
520           case GCS_VERBW:
521             switch(idCommand-This->verb_offset)
522             {
523             case FCIDM_SHVIEW_RENAME:
524                 MultiByteToWideChar( CP_ACP, 0, "rename", -1, (LPWSTR)lpszName, uMaxNameLen );
525                 hr = S_OK;
526                 break;
527             }
528             break;
529
530           case GCS_VALIDATEA:
531           case GCS_VALIDATEW:
532             hr = S_OK;
533             break;
534         }
535         TRACE("-- (%p)->(name=%s)\n", This, lpszName);
536         return hr;
537 }
538
539 /**************************************************************************
540 * NOTES
541 *  should be only in IContextMenu2 and IContextMenu3
542 *  is nevertheless called from word95
543 */
544 static HRESULT WINAPI ContextMenu_HandleMenuMsg(IContextMenu3 *iface, UINT msg,
545     WPARAM wParam, LPARAM lParam)
546 {
547     ContextMenu *This = impl_from_IContextMenu3(iface);
548     FIXME("(%p)->(0x%x 0x%lx 0x%lx): stub\n", This, msg, wParam, lParam);
549     return E_NOTIMPL;
550 }
551
552 static HRESULT WINAPI ContextMenu_HandleMenuMsg2(IContextMenu3 *iface, UINT msg,
553     WPARAM wParam, LPARAM lParam, LRESULT *result)
554 {
555     ContextMenu *This = impl_from_IContextMenu3(iface);
556     FIXME("(%p)->(0x%x 0x%lx 0x%lx %p): stub\n", This, msg, wParam, lParam, result);
557     return E_NOTIMPL;
558 }
559
560 static const IContextMenu3Vtbl ItemContextMenuVtbl =
561 {
562     ContextMenu_QueryInterface,
563     ContextMenu_AddRef,
564     ContextMenu_Release,
565     ItemMenu_QueryContextMenu,
566     ItemMenu_InvokeCommand,
567     ItemMenu_GetCommandString,
568     ContextMenu_HandleMenuMsg,
569     ContextMenu_HandleMenuMsg2
570 };
571
572 HRESULT ItemMenu_Constructor(IShellFolder *parent, LPCITEMIDLIST pidl, const LPCITEMIDLIST *apidl, UINT cidl,
573     REFIID riid, void **pObj)
574 {
575     ContextMenu* This;
576     HRESULT hr;
577     int i;
578
579     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
580     if (!This) return E_OUTOFMEMORY;
581
582     This->IContextMenu3_iface.lpVtbl = &ItemContextMenuVtbl;
583     This->ref = 1;
584     This->verb_offset = 0;
585     This->parent = parent;
586     if (parent) IShellFolder_AddRef(parent);
587
588     This->pidl = ILClone(pidl);
589     This->apidl = _ILCopyaPidl(apidl, cidl);
590     This->cidl = cidl;
591     This->allvalues = TRUE;
592
593     This->desktop = FALSE;
594
595     for (i = 0; i < cidl; i++)
596        This->allvalues &= (_ILIsValue(apidl[i]) ? 1 : 0);
597
598     hr = IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, pObj);
599     IContextMenu3_Release(&This->IContextMenu3_iface);
600
601     return hr;
602 }
603
604 /* Background menu implementation */
605 static HRESULT WINAPI BackgroundMenu_QueryContextMenu(
606         IContextMenu3 *iface,
607         HMENU hMenu,
608         UINT indexMenu,
609         UINT idCmdFirst,
610         UINT idCmdLast,
611         UINT uFlags)
612 {
613     ContextMenu *This = impl_from_IContextMenu3(iface);
614     HMENU hMyMenu;
615     UINT idMax;
616     HRESULT hr;
617
618     TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",
619           This, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
620
621     This->verb_offset = idCmdFirst;
622
623     hMyMenu = LoadMenuA(shell32_hInstance, "MENU_002");
624     if (uFlags & CMF_DEFAULTONLY)
625     {
626         HMENU ourMenu = GetSubMenu(hMyMenu,0);
627         UINT oldDef = GetMenuDefaultItem(hMenu,TRUE,GMDI_USEDISABLED);
628         UINT newDef = GetMenuDefaultItem(ourMenu,TRUE,GMDI_USEDISABLED);
629         if (newDef != oldDef)
630             SetMenuDefaultItem(hMenu,newDef,TRUE);
631         if (newDef!=0xFFFFFFFF)
632             hr =  MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, newDef+1);
633         else
634             hr =  MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
635     }
636     else
637     {
638         idMax = Shell_MergeMenus (hMenu, GetSubMenu(hMyMenu,0), indexMenu,
639                                   idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS);
640         hr =  MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, idMax-idCmdFirst);
641     }
642     DestroyMenu(hMyMenu);
643
644     TRACE("(%p)->returning 0x%x\n",This,hr);
645     return hr;
646 }
647
648 static void DoNewFolder(ContextMenu *This, IShellView *view)
649 {
650     ISFHelper *helper;
651
652     IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&helper);
653     if (helper)
654     {
655         WCHAR nameW[MAX_PATH];
656         LPITEMIDLIST pidl;
657
658         ISFHelper_GetUniqueName(helper, nameW, MAX_PATH);
659         ISFHelper_AddFolder(helper, 0, nameW, &pidl);
660
661         if (view)
662         {
663             /* if we are in a shellview do labeledit */
664             IShellView_SelectItem(view,
665                     pidl,(SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE
666                     |SVSI_FOCUSED|SVSI_SELECT));
667         }
668
669         SHFree(pidl);
670         ISFHelper_Release(helper);
671     }
672 }
673
674 static BOOL DoPaste(ContextMenu *This)
675 {
676         BOOL bSuccess = FALSE;
677         IDataObject * pda;
678
679         TRACE("\n");
680
681         if(SUCCEEDED(OleGetClipboard(&pda)))
682         {
683           STGMEDIUM medium;
684           FORMATETC formatetc;
685
686           TRACE("pda=%p\n", pda);
687
688           /* Set the FORMATETC structure*/
689           InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLISTW), TYMED_HGLOBAL);
690
691           /* Get the pidls from IDataObject */
692           if(SUCCEEDED(IDataObject_GetData(pda,&formatetc,&medium)))
693           {
694             LPITEMIDLIST * apidl;
695             LPITEMIDLIST pidl;
696             IShellFolder *psfFrom = NULL, *psfDesktop;
697
698             LPIDA lpcida = GlobalLock(medium.u.hGlobal);
699             TRACE("cida=%p\n", lpcida);
700
701             apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
702
703             /* bind to the source shellfolder */
704             SHGetDesktopFolder(&psfDesktop);
705             if(psfDesktop)
706             {
707               IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (LPVOID*)&psfFrom);
708               IShellFolder_Release(psfDesktop);
709             }
710
711             if (psfFrom)
712             {
713               /* get source and destination shellfolder */
714               ISFHelper *psfhlpdst, *psfhlpsrc;
715               IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&psfhlpdst);
716               IShellFolder_QueryInterface(psfFrom, &IID_ISFHelper, (void**)&psfhlpsrc);
717
718               /* do the copy/move */
719               if (psfhlpdst && psfhlpsrc)
720               {
721                 ISFHelper_CopyItems(psfhlpdst, psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl);
722                 /* FIXME handle move
723                 ISFHelper_DeleteItems(psfhlpsrc, lpcida->cidl, apidl);
724                 */
725               }
726               if(psfhlpdst) ISFHelper_Release(psfhlpdst);
727               if(psfhlpsrc) ISFHelper_Release(psfhlpsrc);
728               IShellFolder_Release(psfFrom);
729             }
730
731             _ILFreeaPidl(apidl, lpcida->cidl);
732             SHFree(pidl);
733
734             /* release the medium*/
735             ReleaseStgMedium(&medium);
736           }
737           IDataObject_Release(pda);
738         }
739 #if 0
740         HGLOBAL  hMem;
741
742         OpenClipboard(NULL);
743         hMem = GetClipboardData(CF_HDROP);
744
745         if(hMem)
746         {
747           char * pDropFiles = GlobalLock(hMem);
748           if(pDropFiles)
749           {
750             int len, offset = sizeof(DROPFILESTRUCT);
751
752             while( pDropFiles[offset] != 0)
753             {
754               len = strlen(pDropFiles + offset);
755               TRACE("%s\n", pDropFiles + offset);
756               offset += len+1;
757             }
758           }
759           GlobalUnlock(hMem);
760         }
761         CloseClipboard();
762 #endif
763         return bSuccess;
764 }
765
766 static HRESULT WINAPI BackgroundMenu_InvokeCommand(
767         IContextMenu3 *iface,
768         LPCMINVOKECOMMANDINFO lpcmi)
769 {
770     ContextMenu *This = impl_from_IContextMenu3(iface);
771     IShellBrowser *browser;
772     IShellView *view = NULL;
773     HWND hWnd = NULL;
774
775     TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", This, lpcmi, lpcmi->lpVerb, lpcmi->hwnd);
776
777     /* get the active IShellView */
778     if ((browser = (IShellBrowser*)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0)))
779     {
780         if (SUCCEEDED(IShellBrowser_QueryActiveShellView(browser, &view)))
781             IShellView_GetWindow(view, &hWnd);
782     }
783
784     if(HIWORD(lpcmi->lpVerb))
785     {
786         TRACE("%s\n", debugstr_a(lpcmi->lpVerb));
787
788         if (!strcmp(lpcmi->lpVerb, CMDSTR_NEWFOLDERA))
789         {
790             DoNewFolder(This, view);
791         }
792         else if (!strcmp(lpcmi->lpVerb, CMDSTR_VIEWLISTA))
793         {
794             if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_LISTVIEW, 0), 0);
795         }
796         else if (!strcmp(lpcmi->lpVerb, CMDSTR_VIEWDETAILSA))
797         {
798             if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_REPORTVIEW, 0), 0);
799         }
800         else
801         {
802             FIXME("please report: unknown verb %s\n", debugstr_a(lpcmi->lpVerb));
803         }
804     }
805     else
806     {
807         switch (LOWORD(lpcmi->lpVerb) - This->verb_offset)
808         {
809             case FCIDM_SHVIEW_REFRESH:
810                 if (view) IShellView_Refresh(view);
811                 break;
812
813             case FCIDM_SHVIEW_NEWFOLDER:
814                 DoNewFolder(This, view);
815                 break;
816
817             case FCIDM_SHVIEW_INSERT:
818                 DoPaste(This);
819                 break;
820
821             case FCIDM_SHVIEW_PROPERTIES:
822                 if (This->desktop) {
823                     ShellExecuteA(lpcmi->hwnd, "open", "rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL);
824                 } else {
825                     FIXME("launch item properties dialog\n");
826                 }
827                 break;
828
829             default:
830                 /* if it's an id just pass it to the parent shv */
831                 if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0);
832                 break;
833          }
834     }
835
836     if (view)
837         IShellView_Release(view);
838
839     return S_OK;
840 }
841
842 static HRESULT WINAPI BackgroundMenu_GetCommandString(
843         IContextMenu3 *iface,
844         UINT_PTR idCommand,
845         UINT uFlags,
846         UINT* lpReserved,
847         LPSTR lpszName,
848         UINT uMaxNameLen)
849 {
850         ContextMenu *This = impl_from_IContextMenu3(iface);
851
852         TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
853
854         /* test the existence of the menu items, the file dialog enables
855            the buttons according to this */
856         if (uFlags == GCS_VALIDATEA)
857         {
858           if(HIWORD(idCommand))
859           {
860             if (!strcmp((LPSTR)idCommand, CMDSTR_VIEWLISTA) ||
861                 !strcmp((LPSTR)idCommand, CMDSTR_VIEWDETAILSA) ||
862                 !strcmp((LPSTR)idCommand, CMDSTR_NEWFOLDERA))
863             {
864               return S_OK;
865             }
866           }
867         }
868
869         FIXME("unknown command string\n");
870         return E_FAIL;
871 }
872
873 static const IContextMenu3Vtbl BackgroundContextMenuVtbl =
874 {
875     ContextMenu_QueryInterface,
876     ContextMenu_AddRef,
877     ContextMenu_Release,
878     BackgroundMenu_QueryContextMenu,
879     BackgroundMenu_InvokeCommand,
880     BackgroundMenu_GetCommandString,
881     ContextMenu_HandleMenuMsg,
882     ContextMenu_HandleMenuMsg2
883 };
884
885 HRESULT BackgroundMenu_Constructor(IShellFolder *parent, BOOL desktop, REFIID riid, void **pObj)
886 {
887     ContextMenu *This;
888     HRESULT hr;
889
890     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
891     if (!This) return E_OUTOFMEMORY;
892
893     This->IContextMenu3_iface.lpVtbl = &BackgroundContextMenuVtbl;
894     This->ref = 1;
895     This->parent = parent;
896     This->verb_offset = 0;
897
898     This->pidl = NULL;
899     This->apidl = NULL;
900     This->cidl = 0;
901     This->allvalues = FALSE;
902
903     This->desktop = desktop;
904     if (parent) IShellFolder_AddRef(parent);
905
906     hr = IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, pObj);
907     IContextMenu3_Release(&This->IContextMenu3_iface);
908
909     return hr;
910 }