fdopen: don't rewind the file after creating the FILE* handle. Added
[wine] / dlls / shell32 / shv_item_cmenu.c
1 /*
2  *      IContextMenu for items in the shellview
3  *
4  * Copyright 1998, 2000 Juergen Schmied <juergen.schmied@debitel.net>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <string.h>
22
23 #include "winerror.h"
24 #include "wine/debug.h"
25
26 #include "pidl.h"
27 #include "shlguid.h"
28 #include "undocshell.h"
29 #include "shlobj.h"
30
31 #include "shell32_main.h"
32 #include "shellfolder.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(shell);
35
36 /**************************************************************************
37 *  IContextMenu Implementation
38 */
39 typedef struct
40 {       ICOM_VFIELD(IContextMenu);
41         DWORD           ref;
42         IShellFolder*   pSFParent;
43         LPITEMIDLIST    pidl;           /* root pidl */
44         LPITEMIDLIST    *apidl;         /* array of child pidls */
45         UINT            cidl;
46         BOOL            bAllValues;
47 } ItemCmImpl;
48
49
50 static struct ICOM_VTABLE(IContextMenu) cmvt;
51
52 /**************************************************************************
53 * ISvItemCm_CanRenameItems()
54 */
55 static BOOL ISvItemCm_CanRenameItems(ItemCmImpl *This)
56 {       UINT  i;
57         DWORD dwAttributes;
58
59         TRACE("(%p)->()\n",This);
60
61         if(This->apidl)
62         {
63           for(i = 0; i < This->cidl; i++){}
64           if(i > 1) return FALSE;               /* can't rename more than one item at a time*/
65           dwAttributes = SFGAO_CANRENAME;
66           IShellFolder_GetAttributesOf(This->pSFParent, 1, This->apidl, &dwAttributes);
67           return dwAttributes & SFGAO_CANRENAME;
68         }
69         return FALSE;
70 }
71
72 /**************************************************************************
73 *   ISvItemCm_Constructor()
74 */
75 IContextMenu *ISvItemCm_Constructor(LPSHELLFOLDER pSFParent, LPCITEMIDLIST pidl, LPCITEMIDLIST *apidl, UINT cidl)
76 {       ItemCmImpl* cm;
77         UINT  u;
78
79         cm = (ItemCmImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ItemCmImpl));
80         ICOM_VTBL(cm)=&cmvt;
81         cm->ref = 1;
82         cm->pidl = ILClone(pidl);
83         cm->pSFParent = pSFParent;
84
85         if(pSFParent) IShellFolder_AddRef(pSFParent);
86
87         cm->apidl = _ILCopyaPidl(apidl, cidl);
88         cm->cidl = cidl;
89
90         cm->bAllValues = 1;
91         for(u = 0; u < cidl; u++)
92         {
93           cm->bAllValues &= (_ILIsValue(apidl[u]) ? 1 : 0);
94         }
95
96         TRACE("(%p)->()\n",cm);
97
98         return (IContextMenu*)cm;
99 }
100
101 /**************************************************************************
102 *  ISvItemCm_fnQueryInterface
103 */
104 static HRESULT WINAPI ISvItemCm_fnQueryInterface(IContextMenu *iface, REFIID riid, LPVOID *ppvObj)
105 {
106         ICOM_THIS(ItemCmImpl, iface);
107
108         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
109
110         *ppvObj = NULL;
111
112         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
113         {
114           *ppvObj = This;
115         }
116         else if(IsEqualIID(riid, &IID_IContextMenu))  /*IContextMenu*/
117         {
118           *ppvObj = This;
119         }
120         else if(IsEqualIID(riid, &IID_IShellExtInit))  /*IShellExtInit*/
121         {
122           FIXME("-- LPSHELLEXTINIT pointer requested\n");
123         }
124
125         if(*ppvObj)
126         {
127           IUnknown_AddRef((IUnknown*)*ppvObj);
128           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
129           return S_OK;
130         }
131         TRACE("-- Interface: E_NOINTERFACE\n");
132         return E_NOINTERFACE;
133 }
134
135 /**************************************************************************
136 *  ISvItemCm_fnAddRef
137 */
138 static ULONG WINAPI ISvItemCm_fnAddRef(IContextMenu *iface)
139 {
140         ICOM_THIS(ItemCmImpl, iface);
141
142         TRACE("(%p)->(count=%lu)\n",This, This->ref);
143
144         return ++(This->ref);
145 }
146
147 /**************************************************************************
148 *  ISvItemCm_fnRelease
149 */
150 static ULONG WINAPI ISvItemCm_fnRelease(IContextMenu *iface)
151 {
152         ICOM_THIS(ItemCmImpl, iface);
153
154         TRACE("(%p)->()\n",This);
155
156         if (!--(This->ref))
157         {
158           TRACE(" destroying IContextMenu(%p)\n",This);
159
160           if(This->pSFParent)
161             IShellFolder_Release(This->pSFParent);
162
163           if(This->pidl)
164             SHFree(This->pidl);
165
166           /*make sure the pidl is freed*/
167           _ILFreeaPidl(This->apidl, This->cidl);
168
169           HeapFree(GetProcessHeap(),0,This);
170           return 0;
171         }
172         return This->ref;
173 }
174
175 /**************************************************************************
176 *  ICM_InsertItem()
177 */
178 void WINAPI _InsertMenuItem (
179         HMENU hmenu,
180         UINT indexMenu,
181         BOOL fByPosition,
182         UINT wID,
183         UINT fType,
184         LPSTR dwTypeData,
185         UINT fState)
186 {
187         MENUITEMINFOA   mii;
188
189         ZeroMemory(&mii, sizeof(mii));
190         mii.cbSize = sizeof(mii);
191         if (fType == MFT_SEPARATOR)
192         {
193           mii.fMask = MIIM_ID | MIIM_TYPE;
194         }
195         else
196         {
197           mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
198           mii.dwTypeData = dwTypeData;
199           mii.fState = fState;
200         }
201         mii.wID = wID;
202         mii.fType = fType;
203         InsertMenuItemA( hmenu, indexMenu, fByPosition, &mii);
204 }
205 /**************************************************************************
206 * ISvItemCm_fnQueryContextMenu()
207 */
208
209 static HRESULT WINAPI ISvItemCm_fnQueryContextMenu(
210         IContextMenu *iface,
211         HMENU hmenu,
212         UINT indexMenu,
213         UINT idCmdFirst,
214         UINT idCmdLast,
215         UINT uFlags)
216 {
217         ICOM_THIS(ItemCmImpl, iface);
218
219         TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",This, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
220
221         if(!(CMF_DEFAULTONLY & uFlags))
222         {
223           if(uFlags & CMF_EXPLORE)
224           {
225             if(This->bAllValues)
226             {
227               _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_OPEN, MFT_STRING, "&Open", MFS_ENABLED);
228               _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_EXPLORE, MFT_STRING, "&Explore", MFS_ENABLED|MFS_DEFAULT);
229             }
230             else
231             {
232               _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_EXPLORE, MFT_STRING, "&Explore", MFS_ENABLED|MFS_DEFAULT);
233               _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_OPEN, MFT_STRING, "&Open", MFS_ENABLED);
234             }
235           }
236           else
237           {
238             _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_OPEN, MFT_STRING, "&Select", MFS_ENABLED|MFS_DEFAULT);
239           }
240           _InsertMenuItem(hmenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
241           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_COPY, MFT_STRING, "&Copy", MFS_ENABLED);
242           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_CUT, MFT_STRING, "&Cut", MFS_ENABLED);
243
244           _InsertMenuItem(hmenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
245           _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_DELETE, MFT_STRING, "&Delete", MFS_ENABLED);
246
247           if(uFlags & CMF_CANRENAME)
248             _InsertMenuItem(hmenu, indexMenu++, TRUE, FCIDM_SHVIEW_RENAME, MFT_STRING, "&Rename", ISvItemCm_CanRenameItems(This) ? MFS_ENABLED : MFS_DISABLED);
249
250           return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (FCIDM_SHVIEWLAST));
251         }
252         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
253 }
254
255 /**************************************************************************
256 * DoOpenExplore
257 *
258 *  for folders only
259 */
260
261 static void DoOpenExplore(
262         IContextMenu *iface,
263         HWND hwnd,
264         LPCSTR verb)
265 {
266         ICOM_THIS(ItemCmImpl, iface);
267
268         UINT i, bFolderFound = FALSE;
269         LPITEMIDLIST    pidlFQ;
270         SHELLEXECUTEINFOA       sei;
271
272         /* Find the first item in the list that is not a value. These commands
273             should never be invoked if there isn't at least one folder item in the list.*/
274
275         for(i = 0; i<This->cidl; i++)
276         {
277           if(!_ILIsValue(This->apidl[i]))
278           {
279             bFolderFound = TRUE;
280             break;
281           }
282         }
283
284         if (!bFolderFound) return;
285
286         pidlFQ = ILCombine(This->pidl, This->apidl[i]);
287
288         ZeroMemory(&sei, sizeof(sei));
289         sei.cbSize = sizeof(sei);
290         sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME;
291         sei.lpIDList = pidlFQ;
292         sei.lpClass = "folder";
293         sei.hwnd = hwnd;
294         sei.nShow = SW_SHOWNORMAL;
295         sei.lpVerb = verb;
296         ShellExecuteExA(&sei);
297         SHFree(pidlFQ);
298 }
299
300 /**************************************************************************
301 * DoRename
302 */
303 static void DoRename(
304         IContextMenu *iface,
305         HWND hwnd)
306 {
307         ICOM_THIS(ItemCmImpl, iface);
308
309         LPSHELLBROWSER  lpSB;
310         LPSHELLVIEW     lpSV;
311
312         TRACE("(%p)->(wnd=%p)\n",This, hwnd);
313
314         /* get the active IShellView */
315         if ((lpSB = (LPSHELLBROWSER)SendMessageA(hwnd, CWM_GETISHELLBROWSER,0,0)))
316         {
317           if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))
318           {
319             TRACE("(sv=%p)\n",lpSV);
320             IShellView_SelectItem(lpSV, This->apidl[0],
321               SVSI_DESELECTOTHERS|SVSI_EDIT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_SELECT);
322             IShellView_Release(lpSV);
323           }
324         }
325 }
326
327 /**************************************************************************
328  * DoDelete
329  *
330  * deletes the currently selected items
331  */
332 static void DoDelete(IContextMenu *iface)
333 {
334         ICOM_THIS(ItemCmImpl, iface);
335         ISFHelper * psfhlp;
336
337         IShellFolder_QueryInterface(This->pSFParent, &IID_ISFHelper, (LPVOID*)&psfhlp);
338         if (psfhlp)
339         {
340           ISFHelper_DeleteItems(psfhlp, This->cidl, This->apidl);
341           ISFHelper_Release(psfhlp);
342         }
343 }
344
345 /**************************************************************************
346  * DoCopyOrCut
347  *
348  * copies the currently selected items into the clipboard
349  */
350 static BOOL DoCopyOrCut(
351         IContextMenu *iface,
352         HWND hwnd,
353         BOOL bCut)
354 {
355         ICOM_THIS(ItemCmImpl, iface);
356
357         LPSHELLBROWSER  lpSB;
358         LPSHELLVIEW     lpSV;
359         LPDATAOBJECT    lpDo;
360
361         TRACE("(%p)->(wnd=%p,bCut=0x%08x)\n",This, hwnd, bCut);
362
363         if(GetShellOle())
364         {
365           /* get the active IShellView */
366           if ((lpSB = (LPSHELLBROWSER)SendMessageA(hwnd, CWM_GETISHELLBROWSER,0,0)))
367           {
368             if (SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))
369             {
370               if (SUCCEEDED(IShellView_GetItemObject(lpSV, SVGIO_SELECTION, &IID_IDataObject, (LPVOID*)&lpDo)))
371               {
372                 pOleSetClipboard(lpDo);
373                 IDataObject_Release(lpDo);
374               }
375               IShellView_Release(lpSV);
376             }
377           }
378         }
379         return TRUE;
380 #if 0
381 /*
382   the following code does the copy operation witout ole32.dll
383   we might need this possibility too (js)
384 */
385         BOOL bSuccess = FALSE;
386
387         TRACE("(%p)\n", iface);
388
389         if(OpenClipboard(NULL))
390         {
391           if(EmptyClipboard())
392           {
393             IPersistFolder2 * ppf2;
394             IShellFolder_QueryInterface(This->pSFParent, &IID_IPersistFolder2, (LPVOID*)&ppf2);
395             if (ppf2)
396             {
397               LPITEMIDLIST pidl;
398               IPersistFolder2_GetCurFolder(ppf2, &pidl);
399               if(pidl)
400               {
401                 HGLOBAL hMem;
402
403                 hMem = RenderHDROP(pidl, This->apidl, This->cidl);
404
405                 if(SetClipboardData(CF_HDROP, hMem))
406                 {
407                   bSuccess = TRUE;
408                 }
409                 SHFree(pidl);
410               }
411               IPersistFolder2_Release(ppf2);
412             }
413
414           }
415           CloseClipboard();
416         }
417         return bSuccess;
418 #endif
419 }
420 /**************************************************************************
421 * ISvItemCm_fnInvokeCommand()
422 */
423 static HRESULT WINAPI ISvItemCm_fnInvokeCommand(
424         IContextMenu *iface,
425         LPCMINVOKECOMMANDINFO lpcmi)
426 {
427         ICOM_THIS(ItemCmImpl, iface);
428
429         TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);
430
431         if(LOWORD(lpcmi->lpVerb) > FCIDM_SHVIEWLAST)  return E_INVALIDARG;
432
433         switch(LOWORD(lpcmi->lpVerb))
434         {
435           case FCIDM_SHVIEW_EXPLORE:
436             DoOpenExplore(iface, lpcmi->hwnd, "explore");
437             break;
438           case FCIDM_SHVIEW_OPEN:
439             DoOpenExplore(iface, lpcmi->hwnd, "open");
440             break;
441           case FCIDM_SHVIEW_RENAME:
442             DoRename(iface, lpcmi->hwnd);
443             break;
444           case FCIDM_SHVIEW_DELETE:
445             DoDelete(iface);
446             break;
447           case FCIDM_SHVIEW_COPY:
448             DoCopyOrCut(iface, lpcmi->hwnd, FALSE);
449             break;
450           case FCIDM_SHVIEW_CUT:
451             DoCopyOrCut(iface, lpcmi->hwnd, TRUE);
452             break;
453         }
454         return NOERROR;
455 }
456
457 /**************************************************************************
458 *  ISvItemCm_fnGetCommandString()
459 */
460 static HRESULT WINAPI ISvItemCm_fnGetCommandString(
461         IContextMenu *iface,
462         UINT idCommand,
463         UINT uFlags,
464         UINT* lpReserved,
465         LPSTR lpszName,
466         UINT uMaxNameLen)
467 {
468         ICOM_THIS(ItemCmImpl, iface);
469
470         HRESULT  hr = E_INVALIDARG;
471
472         TRACE("(%p)->(idcom=%x flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
473
474         switch(uFlags)
475         {
476           case GCS_HELPTEXT:
477             hr = E_NOTIMPL;
478             break;
479
480           case GCS_VERBA:
481             switch(idCommand)
482             {
483               case FCIDM_SHVIEW_RENAME:
484                 strcpy((LPSTR)lpszName, "rename");
485                 hr = NOERROR;
486                 break;
487             }
488             break;
489
490              /* NT 4.0 with IE 3.0x or no IE will always call This with GCS_VERBW. In This
491              case, you need to do the lstrcpyW to the pointer passed.*/
492           case GCS_VERBW:
493             switch(idCommand)
494             { case FCIDM_SHVIEW_RENAME:
495                 MultiByteToWideChar( CP_ACP, 0, "rename", -1, (LPWSTR)lpszName, uMaxNameLen );
496                 hr = NOERROR;
497                 break;
498             }
499             break;
500
501           case GCS_VALIDATE:
502             hr = NOERROR;
503             break;
504         }
505         TRACE("-- (%p)->(name=%s)\n",This, lpszName);
506         return hr;
507 }
508
509 /**************************************************************************
510 * ISvItemCm_fnHandleMenuMsg()
511 * NOTES
512 *  should be only in IContextMenu2 and IContextMenu3
513 *  is nevertheless called from word95
514 */
515 static HRESULT WINAPI ISvItemCm_fnHandleMenuMsg(
516         IContextMenu *iface,
517         UINT uMsg,
518         WPARAM wParam,
519         LPARAM lParam)
520 {
521         ICOM_THIS(ItemCmImpl, iface);
522
523         TRACE("(%p)->(msg=%x wp=%x lp=%lx)\n",This, uMsg, wParam, lParam);
524
525         return E_NOTIMPL;
526 }
527
528 static struct ICOM_VTABLE(IContextMenu) cmvt =
529 {
530         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
531         ISvItemCm_fnQueryInterface,
532         ISvItemCm_fnAddRef,
533         ISvItemCm_fnRelease,
534         ISvItemCm_fnQueryContextMenu,
535         ISvItemCm_fnInvokeCommand,
536         ISvItemCm_fnGetCommandString,
537         ISvItemCm_fnHandleMenuMsg,
538         (void *) 0xdeadbabe     /* just paranoia */
539 };