Authors: Rob Shearman <rob@codeweavers.com>, Mike Hearn <mh@codeweavers.com>
[wine] / dlls / shell32 / shv_bg_cmenu.c
1 /*
2  *      IContextMenu
3  *      ShellView Background Context Menu (shv_bg_cm)
4  *
5  *      Copyright 1999  Juergen Schmied <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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 #include <string.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26
27 #include "wine/debug.h"
28
29 #include "windef.h"
30 #include "wingdi.h"
31 #include "pidl.h"
32 #include "shlguid.h"
33 #include "shlobj.h"
34
35 #include "shell32_main.h"
36 #include "shellfolder.h"
37 #include "undocshell.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(shell);
40
41 /**************************************************************************
42 *  IContextMenu Implementation
43 */
44 typedef struct
45 {
46         IContextMenu2Vtbl *lpVtbl;
47         IShellFolder*   pSFParent;
48         DWORD           ref;
49 } BgCmImpl;
50
51
52 static struct IContextMenu2Vtbl cmvt;
53
54 /**************************************************************************
55 *   ISVBgCm_Constructor()
56 */
57 IContextMenu2 *ISvBgCm_Constructor(IShellFolder*        pSFParent)
58 {
59         BgCmImpl* cm;
60
61         cm = (BgCmImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(BgCmImpl));
62         cm->lpVtbl = &cmvt;
63         cm->ref = 1;
64         cm->pSFParent = pSFParent;
65         if(pSFParent) IShellFolder_AddRef(pSFParent);
66
67         TRACE("(%p)->()\n",cm);
68         return (IContextMenu2*)cm;
69 }
70
71 /**************************************************************************
72 *  ISVBgCm_fnQueryInterface
73 */
74 static HRESULT WINAPI ISVBgCm_fnQueryInterface(IContextMenu2 *iface, REFIID riid, LPVOID *ppvObj)
75 {
76         BgCmImpl *This = (BgCmImpl *)iface;
77
78         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
79
80         *ppvObj = NULL;
81
82         if(IsEqualIID(riid, &IID_IUnknown) ||
83            IsEqualIID(riid, &IID_IContextMenu) ||
84            IsEqualIID(riid, &IID_IContextMenu2))
85         {
86           *ppvObj = This;
87         }
88         else if(IsEqualIID(riid, &IID_IShellExtInit))  /*IShellExtInit*/
89         {
90           FIXME("-- LPSHELLEXTINIT pointer requested\n");
91         }
92
93         if(*ppvObj)
94         {
95           IUnknown_AddRef((IUnknown*)*ppvObj);
96           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
97           return S_OK;
98         }
99         TRACE("-- Interface: E_NOINTERFACE\n");
100         return E_NOINTERFACE;
101 }
102
103 /**************************************************************************
104 *  ISVBgCm_fnAddRef
105 */
106 static ULONG WINAPI ISVBgCm_fnAddRef(IContextMenu2 *iface)
107 {
108         BgCmImpl *This = (BgCmImpl *)iface;
109         ULONG refCount = InterlockedIncrement(&This->ref);
110
111         TRACE("(%p)->(count=%lu)\n", This, refCount - 1);
112
113         return refCount;
114 }
115
116 /**************************************************************************
117 *  ISVBgCm_fnRelease
118 */
119 static ULONG WINAPI ISVBgCm_fnRelease(IContextMenu2 *iface)
120 {
121         BgCmImpl *This = (BgCmImpl *)iface;
122         ULONG refCount = InterlockedDecrement(&This->ref);
123
124         TRACE("(%p)->(count=%li)\n", This, refCount + 1);
125
126         if (!refCount)
127         {
128           TRACE(" destroying IContextMenu(%p)\n",This);
129
130           if(This->pSFParent)
131             IShellFolder_Release(This->pSFParent);
132
133           HeapFree(GetProcessHeap(),0,This);
134         }
135         return refCount;
136 }
137
138 /**************************************************************************
139 * ISVBgCm_fnQueryContextMenu()
140 */
141
142 static HRESULT WINAPI ISVBgCm_fnQueryContextMenu(
143         IContextMenu2 *iface,
144         HMENU hMenu,
145         UINT indexMenu,
146         UINT idCmdFirst,
147         UINT idCmdLast,
148         UINT uFlags)
149 {
150     HMENU       hMyMenu;
151     UINT        idMax;
152     HRESULT hr;
153
154     BgCmImpl *This = (BgCmImpl *)iface;
155
156     TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",
157           This, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
158
159
160     hMyMenu = LoadMenuA(shell32_hInstance, "MENU_002");
161     if (uFlags & CMF_DEFAULTONLY)
162     {
163         HMENU ourMenu = GetSubMenu(hMyMenu,0);
164         UINT oldDef = GetMenuDefaultItem(hMenu,TRUE,GMDI_USEDISABLED);
165         UINT newDef = GetMenuDefaultItem(ourMenu,TRUE,GMDI_USEDISABLED);
166         if (newDef != oldDef)
167             SetMenuDefaultItem(hMenu,newDef,TRUE);
168         if (newDef!=0xFFFFFFFF)
169             hr =  MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, newDef+1);
170         else
171             hr =  MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
172     }
173     else
174     {
175         idMax = Shell_MergeMenus (hMenu, GetSubMenu(hMyMenu,0), indexMenu,
176                                   idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS);
177         hr =  MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, idMax-idCmdFirst+1);
178     }
179     DestroyMenu(hMyMenu);
180
181     TRACE("(%p)->returning 0x%lx\n",This,hr);
182     return hr;
183 }
184
185 /**************************************************************************
186 * DoNewFolder
187 */
188 static void DoNewFolder(
189         IContextMenu2 *iface,
190         IShellView *psv)
191 {
192         BgCmImpl *This = (BgCmImpl *)iface;
193         ISFHelper * psfhlp;
194         char szName[MAX_PATH];
195
196         IShellFolder_QueryInterface(This->pSFParent, &IID_ISFHelper, (LPVOID*)&psfhlp);
197         if (psfhlp)
198         {
199           LPITEMIDLIST pidl;
200           ISFHelper_GetUniqueName(psfhlp, szName, MAX_PATH);
201           ISFHelper_AddFolder(psfhlp, 0, szName, &pidl);
202
203           if(psv)
204           {
205             /* if we are in a shellview do labeledit */
206             IShellView_SelectItem(psv,
207                     pidl,(SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE
208                     |SVSI_FOCUSED|SVSI_SELECT));
209           }
210           SHFree(pidl);
211
212           ISFHelper_Release(psfhlp);
213         }
214 }
215
216 /**************************************************************************
217 * DoPaste
218 */
219 static BOOL DoPaste(
220         IContextMenu2 *iface)
221 {
222         BgCmImpl *This = (BgCmImpl *)iface;
223         BOOL bSuccess = FALSE;
224         IDataObject * pda;
225
226         TRACE("\n");
227
228         if(SUCCEEDED(OleGetClipboard(&pda)))
229         {
230           STGMEDIUM medium;
231           FORMATETC formatetc;
232
233           TRACE("pda=%p\n", pda);
234
235           /* Set the FORMATETC structure*/
236           InitFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
237
238           /* Get the pidls from IDataObject */
239           if(SUCCEEDED(IDataObject_GetData(pda,&formatetc,&medium)))
240           {
241             LPITEMIDLIST * apidl;
242             LPITEMIDLIST pidl;
243             IShellFolder *psfFrom = NULL, *psfDesktop;
244
245             LPIDA lpcida = GlobalLock(medium.u.hGlobal);
246             TRACE("cida=%p\n", lpcida);
247
248             apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
249
250             /* bind to the source shellfolder */
251             SHGetDesktopFolder(&psfDesktop);
252             if(psfDesktop)
253             {
254               IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (LPVOID*)&psfFrom);
255               IShellFolder_Release(psfDesktop);
256             }
257
258             if (psfFrom)
259             {
260               /* get source and destination shellfolder */
261               ISFHelper *psfhlpdst, *psfhlpsrc;
262               IShellFolder_QueryInterface(This->pSFParent, &IID_ISFHelper, (LPVOID*)&psfhlpdst);
263               IShellFolder_QueryInterface(psfFrom, &IID_ISFHelper, (LPVOID*)&psfhlpsrc);
264
265               /* do the copy/move */
266               if (psfhlpdst && psfhlpsrc)
267               {
268                 ISFHelper_CopyItems(psfhlpdst, psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl);
269                 /* FIXME handle move
270                 ISFHelper_DeleteItems(psfhlpsrc, lpcida->cidl, apidl);
271                 */
272               }
273               if(psfhlpdst) ISFHelper_Release(psfhlpdst);
274               if(psfhlpsrc) ISFHelper_Release(psfhlpsrc);
275               IShellFolder_Release(psfFrom);
276             }
277
278             _ILFreeaPidl(apidl, lpcida->cidl);
279             SHFree(pidl);
280
281             /* release the medium*/
282             ReleaseStgMedium(&medium);
283           }
284           IDataObject_Release(pda);
285         }
286 #if 0
287         HGLOBAL  hMem;
288
289         OpenClipboard(NULL);
290         hMem = GetClipboardData(CF_HDROP);
291
292         if(hMem)
293         {
294           char * pDropFiles = (char *)GlobalLock(hMem);
295           if(pDropFiles)
296           {
297             int len, offset = sizeof(DROPFILESTRUCT);
298
299             while( pDropFiles[offset] != 0)
300             {
301               len = strlen(pDropFiles + offset);
302               TRACE("%s\n", pDropFiles + offset);
303               offset += len+1;
304             }
305           }
306           GlobalUnlock(hMem);
307         }
308         CloseClipboard();
309 #endif
310         return bSuccess;
311 }
312
313 /**************************************************************************
314 * ISVBgCm_fnInvokeCommand()
315 */
316 static HRESULT WINAPI ISVBgCm_fnInvokeCommand(
317         IContextMenu2 *iface,
318         LPCMINVOKECOMMANDINFO lpcmi)
319 {
320         BgCmImpl *This = (BgCmImpl *)iface;
321
322         LPSHELLBROWSER  lpSB;
323         LPSHELLVIEW lpSV = NULL;
324         HWND hWndSV = 0;
325
326         TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);
327
328         /* get the active IShellView */
329         if((lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0)))
330         {
331           if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))
332           {
333             IShellView_GetWindow(lpSV, &hWndSV);
334           }
335         }
336
337           if(HIWORD(lpcmi->lpVerb))
338           {
339             TRACE("%s\n",lpcmi->lpVerb);
340
341             if (! strcmp(lpcmi->lpVerb,CMDSTR_NEWFOLDERA))
342             {
343                 DoNewFolder(iface, lpSV);
344             }
345             else if (! strcmp(lpcmi->lpVerb,CMDSTR_VIEWLISTA))
346             {
347               if(hWndSV) SendMessageA(hWndSV, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_LISTVIEW,0),0 );
348             }
349             else if (! strcmp(lpcmi->lpVerb,CMDSTR_VIEWDETAILSA))
350             {
351               if(hWndSV) SendMessageA(hWndSV, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_REPORTVIEW,0),0 );
352             }
353             else
354             {
355               FIXME("please report: unknown verb %s\n",lpcmi->lpVerb);
356             }
357           }
358           else
359           {
360             switch(LOWORD(lpcmi->lpVerb))
361             {
362               case FCIDM_SHVIEW_NEWFOLDER:
363                 DoNewFolder(iface, lpSV);
364                 break;
365               case FCIDM_SHVIEW_INSERT:
366                 DoPaste(iface);
367                 break;
368               default:
369                 /* if it's a id just pass it to the parent shv */
370                 SendMessageA(hWndSV, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0),0 );
371                 break;
372             }
373           }
374
375         if (lpSV)
376           IShellView_Release(lpSV);     /* QueryActiveShellView does AddRef*/
377
378         return NOERROR;
379 }
380
381 /**************************************************************************
382  *  ISVBgCm_fnGetCommandString()
383  *
384  */
385 static HRESULT WINAPI ISVBgCm_fnGetCommandString(
386         IContextMenu2 *iface,
387         UINT idCommand,
388         UINT uFlags,
389         UINT* lpReserved,
390         LPSTR lpszName,
391         UINT uMaxNameLen)
392 {
393         BgCmImpl *This = (BgCmImpl *)iface;
394
395         TRACE("(%p)->(idcom=%x flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
396
397         /* test the existence of the menu items, the file dialog enables
398            the buttons according to this */
399         if (uFlags == GCS_VALIDATEA)
400         {
401           if(HIWORD(idCommand))
402           {
403             if (!strcmp((LPSTR)idCommand, CMDSTR_VIEWLISTA) ||
404                 !strcmp((LPSTR)idCommand, CMDSTR_VIEWDETAILSA) ||
405                 !strcmp((LPSTR)idCommand, CMDSTR_NEWFOLDERA))
406             {
407               return NOERROR;
408             }
409           }
410         }
411
412         FIXME("unknown command string\n");
413         return E_FAIL;
414 }
415
416 /**************************************************************************
417 * ISVBgCm_fnHandleMenuMsg()
418 */
419 static HRESULT WINAPI ISVBgCm_fnHandleMenuMsg(
420         IContextMenu2 *iface,
421         UINT uMsg,
422         WPARAM wParam,
423         LPARAM lParam)
424 {
425         BgCmImpl *This = (BgCmImpl *)iface;
426
427         FIXME("(%p)->(msg=%x wp=%x lp=%lx)\n",This, uMsg, wParam, lParam);
428
429         return E_NOTIMPL;
430 }
431
432 /**************************************************************************
433 * IContextMenu2 VTable
434 *
435 */
436 static struct IContextMenu2Vtbl cmvt =
437 {
438         ISVBgCm_fnQueryInterface,
439         ISVBgCm_fnAddRef,
440         ISVBgCm_fnRelease,
441         ISVBgCm_fnQueryContextMenu,
442         ISVBgCm_fnInvokeCommand,
443         ISVBgCm_fnGetCommandString,
444         ISVBgCm_fnHandleMenuMsg
445 };