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