Optimized include/*.h: (recursively) include all headers needed by
[wine] / dlls / shell32 / contmenu.c
1 /*
2  *      IContextMenu
3  *
4  *      Copyright 1998  Juergen Schmied <juergen.schmied@metronet.de>
5  */
6 #include "winerror.h"
7 #include "debug.h"
8
9 #include "pidl.h"
10 #include "objbase.h"
11 #include "if_macros.h"
12 #include "shlguid.h"
13 #include "shell32_main.h"
14 #include "shresdef.h"
15
16 static HRESULT WINAPI IContextMenu_QueryInterface(LPCONTEXTMENU ,REFIID , LPVOID *);
17 static ULONG WINAPI IContextMenu_AddRef(LPCONTEXTMENU);
18 static ULONG WINAPI IContextMenu_Release(LPCONTEXTMENU);
19 static HRESULT WINAPI IContextMenu_QueryContextMenu(LPCONTEXTMENU , HMENU32 ,UINT32 ,UINT32 ,UINT32 ,UINT32);
20 static HRESULT WINAPI IContextMenu_InvokeCommand(LPCONTEXTMENU, LPCMINVOKECOMMANDINFO32);
21 static HRESULT WINAPI IContextMenu_GetCommandString(LPCONTEXTMENU , UINT32 ,UINT32 ,LPUINT32 ,LPSTR ,UINT32);
22 static HRESULT WINAPI IContextMenu_HandleMenuMsg(LPCONTEXTMENU, UINT32, WPARAM32, LPARAM);
23
24 BOOL32 IContextMenu_AllocPidlTable(LPCONTEXTMENU, DWORD);
25 void IContextMenu_FreePidlTable(LPCONTEXTMENU);
26 BOOL32 IContextMenu_CanRenameItems(LPCONTEXTMENU);
27 BOOL32 IContextMenu_FillPidlTable(LPCONTEXTMENU, LPCITEMIDLIST *, UINT32);
28
29 static struct IContextMenu_VTable cmvt = 
30 {       IContextMenu_QueryInterface,
31         IContextMenu_AddRef,
32         IContextMenu_Release,
33         IContextMenu_QueryContextMenu,
34         IContextMenu_InvokeCommand,
35         IContextMenu_GetCommandString,
36         IContextMenu_HandleMenuMsg,
37         (void *) 0xdeadbabe     /* just paranoia */
38 };
39 /**************************************************************************
40 *  IContextMenu_QueryInterface
41 */
42 static HRESULT WINAPI IContextMenu_QueryInterface(LPCONTEXTMENU this,REFIID riid, LPVOID *ppvObj)
43 { char    xriid[50];
44   WINE_StringFromCLSID((LPCLSID)riid,xriid);
45   TRACE(shell,"(%p)->(\n\tIID:\t%s,%p)\n",this,xriid,ppvObj);
46
47   *ppvObj = NULL;
48
49   if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
50   { *ppvObj = (LPUNKNOWN)(LPCONTEXTMENU)this; 
51   }
52   else if(IsEqualIID(riid, &IID_IContextMenu))  /*IContextMenu*/
53   { *ppvObj = (LPCONTEXTMENU)this;
54   }   
55   else if(IsEqualIID(riid, &IID_IShellExtInit))  /*IShellExtInit*/
56   { FIXME (shell,"-- LPSHELLEXTINIT pointer requested\n");
57   }   
58
59   if(*ppvObj)
60   { (*(LPCONTEXTMENU *)ppvObj)->lpvtbl->fnAddRef(this);      
61     TRACE(shell,"-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
62     return S_OK;
63   }
64   TRACE(shell,"-- Interface: E_NOINTERFACE\n");
65   return E_NOINTERFACE;
66 }   
67
68 /**************************************************************************
69 *  IContextMenu_AddRef
70 */
71 static ULONG WINAPI IContextMenu_AddRef(LPCONTEXTMENU this)
72 {       TRACE(shell,"(%p)->(count=%lu)\n",this,(this->ref)+1);
73         shell32_ObjCount++;
74         return ++(this->ref);
75 }
76 /**************************************************************************
77 *  IContextMenu_Release
78 */
79 static ULONG WINAPI IContextMenu_Release(LPCONTEXTMENU this)
80 {       TRACE(shell,"(%p)->()\n",this);
81
82         shell32_ObjCount--;
83
84         if (!--(this->ref)) 
85         { TRACE(shell," destroying IContextMenu(%p)\n",this);
86
87           if(this->pSFParent)
88             this->pSFParent->lpvtbl->fnRelease(this->pSFParent);
89
90           /*make sure the pidl is freed*/
91           if(this->aPidls)
92           { IContextMenu_FreePidlTable(this);
93           }
94
95           HeapFree(GetProcessHeap(),0,this);
96           return 0;
97         }
98         return this->ref;
99 }
100
101 /**************************************************************************
102 *   IContextMenu_Constructor()
103 */
104 LPCONTEXTMENU IContextMenu_Constructor(LPSHELLFOLDER pSFParent, LPCITEMIDLIST *aPidls, UINT32 uItemCount)
105 {       LPCONTEXTMENU cm;
106         UINT32  u;
107     
108         cm = (LPCONTEXTMENU)HeapAlloc(GetProcessHeap(),0,sizeof(IContextMenu));
109         cm->lpvtbl=&cmvt;
110         cm->ref = 1;
111
112         cm->pSFParent = pSFParent;
113         if(cm->pSFParent)
114            cm->pSFParent->lpvtbl->fnAddRef(cm->pSFParent);
115
116         cm->aPidls = NULL;
117
118         IContextMenu_AllocPidlTable(cm, uItemCount);
119     
120         if(cm->aPidls)
121         { IContextMenu_FillPidlTable(cm, aPidls, uItemCount);
122         }
123
124         cm->bAllValues = 1;
125         for(u = 0; u < uItemCount; u++)
126         { cm->bAllValues &= (_ILIsValue(aPidls[u]) ? 1 : 0);
127         }
128         TRACE(shell,"(%p)->()\n",cm);
129         shell32_ObjCount++;
130         return cm;
131 }
132 /**************************************************************************
133 *  ICM_InsertItem()
134 */ 
135 void WINAPI _InsertMenuItem (HMENU32 hmenu, UINT32 indexMenu, BOOL32 fByPosition, 
136                         UINT32 wID, UINT32 fType, LPSTR dwTypeData, UINT32 fState)
137 {       MENUITEMINFO32A mii;
138
139         ZeroMemory(&mii, sizeof(mii));
140         mii.cbSize = sizeof(mii);
141         if (fType == MFT_SEPARATOR)
142         { mii.fMask = MIIM_ID | MIIM_TYPE;
143         }
144         else
145         { mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
146           mii.dwTypeData = dwTypeData;
147           mii.fState = MFS_ENABLED | MFS_DEFAULT;
148         }
149         mii.wID = wID;
150         mii.fType = fType;
151         InsertMenuItem32A( hmenu, indexMenu, fByPosition, &mii);
152 }
153 /**************************************************************************
154 * IContextMenu_QueryContextMenu()
155 */
156
157 static HRESULT WINAPI IContextMenu_QueryContextMenu( LPCONTEXTMENU this, HMENU32 hmenu, UINT32 indexMenu,
158                                                         UINT32 idCmdFirst,UINT32 idCmdLast,UINT32 uFlags)
159 {       BOOL32  fExplore ;
160
161         TRACE(shell,"(%p)->(hmenu=%x indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",this, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
162
163         if(!(CMF_DEFAULTONLY & uFlags))
164         { if(!this->bAllValues) 
165           { /* folder menu */
166             fExplore = uFlags & CMF_EXPLORE;
167             if(fExplore) 
168             { _InsertMenuItem(hmenu, indexMenu++, TRUE, idCmdFirst+IDM_EXPLORE, MFT_STRING, "&Explore", MFS_ENABLED|MFS_DEFAULT);
169               _InsertMenuItem(hmenu, indexMenu++, TRUE, idCmdFirst+IDM_OPEN, MFT_STRING, "&Open", MFS_ENABLED);
170             }
171             else
172             { _InsertMenuItem(hmenu, indexMenu++, TRUE, idCmdFirst+IDM_OPEN, MFT_STRING, "&Open", MFS_ENABLED|MFS_DEFAULT);
173               _InsertMenuItem(hmenu, indexMenu++, TRUE, idCmdFirst+IDM_EXPLORE, MFT_STRING, "&Explore", MFS_ENABLED);
174             }
175
176             if(uFlags & CMF_CANRENAME)
177             { _InsertMenuItem(hmenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
178               _InsertMenuItem(hmenu, indexMenu++, TRUE, idCmdFirst+IDM_RENAME, MFT_STRING, "&Rename", (IContextMenu_CanRenameItems(this) ? MFS_ENABLED : MFS_DISABLED));
179             }
180           }
181           else  /* file menu */
182           { _InsertMenuItem(hmenu, indexMenu++, TRUE, idCmdFirst+IDM_OPEN, MFT_STRING, "&Open", MFS_ENABLED|MFS_DEFAULT);
183             if(uFlags & CMF_CANRENAME)
184             { _InsertMenuItem(hmenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
185               _InsertMenuItem(hmenu, indexMenu++, TRUE, idCmdFirst+IDM_RENAME, MFT_STRING, "&Rename", (IContextMenu_CanRenameItems(this) ? MFS_ENABLED : MFS_DISABLED));
186             }
187           }
188           return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (IDM_LAST + 1));
189         }
190         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
191 }
192
193 /**************************************************************************
194 * IContextMenu_InvokeCommand()
195 */
196 static HRESULT WINAPI IContextMenu_InvokeCommand(LPCONTEXTMENU this, LPCMINVOKECOMMANDINFO32 lpcmi)
197 {       LPITEMIDLIST    pidlTemp,pidlFQ;
198         LPSHELLBROWSER  lpSB;
199         LPSHELLVIEW     lpSV;
200         HWND32  hWndSV;
201         SHELLEXECUTEINFO32A     sei;
202         int   i;
203
204         TRACE(shell,"(%p)->(invcom=%p verb=%p wnd=%x)\n",this,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);    
205
206         if(HIWORD(lpcmi->lpVerb))
207         { /* get the active IShellView */
208           lpSB = (LPSHELLBROWSER)SendMessage32A(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0);
209           IShellBrowser_QueryActiveShellView(lpSB, &lpSV);      /* does AddRef() on lpSV */
210           lpSV->lpvtbl->fnGetWindow(lpSV, &hWndSV);
211           
212           /* these verbs are used by the filedialogs*/
213           if (! strcmp(lpcmi->lpVerb,CMDSTR_NEWFOLDER))
214           { FIXME(shell,"%s\n",lpcmi->lpVerb);
215           }
216           else if (! strcmp(lpcmi->lpVerb,CMDSTR_VIEWLIST))
217           { FIXME(shell,"%s\n",lpcmi->lpVerb);
218             SendMessage32A(hWndSV, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_LISTVIEW,0),0 );
219           }
220           else if (! strcmp(lpcmi->lpVerb,CMDSTR_VIEWDETAILS))
221           { FIXME(shell,"%s\n",lpcmi->lpVerb);
222             SendMessage32A(hWndSV, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_REPORTVIEW,0),0 );
223           } 
224           else
225           { FIXME(shell,"please report: unknown verb %s\n",lpcmi->lpVerb);
226           }
227           lpSV->lpvtbl->fnRelease(lpSV);
228           return NOERROR;
229         }
230
231         if(LOWORD(lpcmi->lpVerb) > IDM_LAST)
232           return E_INVALIDARG;
233
234         switch(LOWORD(lpcmi->lpVerb))
235         { case IDM_EXPLORE:
236           case IDM_OPEN:
237             /* Find the first item in the list that is not a value. These commands 
238             should never be invoked if there isn't at least one folder item in the list.*/
239
240             for(i = 0; this->aPidls[i]; i++)
241             { if(!_ILIsValue(this->aPidls[i]))
242                 break;
243             }
244       
245             pidlTemp = ILCombine(this->pSFParent->mpidl, this->aPidls[i]);
246             pidlFQ = ILCombine(this->pSFParent->pMyPidl, pidlTemp);
247             SHFree(pidlTemp);
248       
249             ZeroMemory(&sei, sizeof(sei));
250             sei.cbSize = sizeof(sei);
251             sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME;
252             sei.lpIDList = pidlFQ;
253             sei.lpClass = "folder";
254             sei.hwnd = lpcmi->hwnd;
255             sei.nShow = SW_SHOWNORMAL;
256       
257             if(LOWORD(lpcmi->lpVerb) == IDM_EXPLORE)
258             { sei.lpVerb = "explore";
259             }
260             else
261             { sei.lpVerb = "open";
262             }
263             ShellExecuteEx32A(&sei);
264             SHFree(pidlFQ);
265             break;
266                 
267           case IDM_RENAME:
268             MessageBeep32(MB_OK);
269             /*handle rename for the view here*/
270             break;          
271         }
272         return NOERROR;
273 }
274
275 /**************************************************************************
276 *  IContextMenu_GetCommandString()
277 */
278 static HRESULT WINAPI IContextMenu_GetCommandString( LPCONTEXTMENU this, UINT32 idCommand,
279                 UINT32 uFlags,LPUINT32 lpReserved,LPSTR lpszName,UINT32 uMaxNameLen)
280 {       HRESULT  hr = E_INVALIDARG;
281
282         TRACE(shell,"(%p)->(idcom=%x flags=%x %p name=%p len=%x)\n",this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
283
284         switch(uFlags)
285         { case GCS_HELPTEXT:
286             hr = E_NOTIMPL;
287             break;
288    
289           case GCS_VERBA:
290             switch(idCommand)
291             { case IDM_RENAME:
292                 strcpy((LPSTR)lpszName, "rename");
293                 hr = NOERROR;
294                 break;
295             }
296             break;
297
298              /* NT 4.0 with IE 3.0x or no IE will always call this with GCS_VERBW. In this 
299              case, you need to do the lstrcpyW to the pointer passed.*/
300           case GCS_VERBW:
301             switch(idCommand)
302             { case IDM_RENAME:
303                 lstrcpyAtoW((LPWSTR)lpszName, "rename");
304                 hr = NOERROR;
305                 break;
306             }
307             break;
308
309           case GCS_VALIDATE:
310             hr = NOERROR;
311             break;
312         }
313         TRACE(shell,"-- (%p)->(name=%s)\n",this, lpszName);
314         return hr;
315 }
316 /**************************************************************************
317 * IContextMenu_HandleMenuMsg()
318 * NOTES
319 *  should be only in IContextMenu2 and IContextMenu3
320 *  is nevertheless called from word95
321 */
322 static HRESULT WINAPI IContextMenu_HandleMenuMsg(LPCONTEXTMENU this, UINT32 uMsg,WPARAM32 wParam,LPARAM lParam)
323 {       TRACE(shell,"(%p)->(msg=%x wp=%x lp=%lx)\n",this, uMsg, wParam, lParam);
324         return E_NOTIMPL;
325 }
326 /**************************************************************************
327 *  IContextMenu_AllocPidlTable()
328 */
329 BOOL32 IContextMenu_AllocPidlTable(LPCONTEXTMENU this, DWORD dwEntries)
330 {       TRACE(shell,"(%p)->(entrys=%lu)\n",this, dwEntries);
331
332         /*add one for NULL terminator */
333         dwEntries++;
334
335         this->aPidls = (LPITEMIDLIST*)SHAlloc(dwEntries * sizeof(LPITEMIDLIST));
336
337         if(this->aPidls)
338         { ZeroMemory(this->aPidls, dwEntries * sizeof(LPITEMIDLIST));   /*set all of the entries to NULL*/
339         }
340         return (this->aPidls != NULL);
341 }
342
343 /**************************************************************************
344 * IContextMenu_FreePidlTable()
345 */
346 void IContextMenu_FreePidlTable(LPCONTEXTMENU this)
347 {       int   i;
348
349         TRACE(shell,"(%p)->()\n",this);
350
351         if(this->aPidls)
352         { for(i = 0; this->aPidls[i]; i++)
353           { SHFree(this->aPidls[i]);
354           }
355    
356           SHFree(this->aPidls);
357           this->aPidls = NULL;
358         }
359 }
360
361 /**************************************************************************
362 * IContextMenu_FillPidlTable()
363 */
364 BOOL32 IContextMenu_FillPidlTable(LPCONTEXTMENU this, LPCITEMIDLIST *aPidls, UINT32 uItemCount)
365 {   UINT32  i;
366         TRACE(shell,"(%p)->(apidl=%p count=%u)\n",this, aPidls, uItemCount);
367         if(this->aPidls)
368         { for(i = 0; i < uItemCount; i++)
369           { this->aPidls[i] = ILClone(aPidls[i]);
370           }
371           return TRUE;
372         }
373         return FALSE;
374 }
375
376 /**************************************************************************
377 * IContextMenu_CanRenameItems()
378 */
379 BOOL32 IContextMenu_CanRenameItems(LPCONTEXTMENU this)
380 {       UINT32  i;
381         DWORD dwAttributes;
382
383         TRACE(shell,"(%p)->()\n",this);
384
385         if(this->aPidls)
386         { for(i = 0; this->aPidls[i]; i++){} /*get the number of items assigned to this object*/
387             if(i > 1)   /*you can't rename more than one item at a time*/
388             { return FALSE;
389             }
390             dwAttributes = SFGAO_CANRENAME;
391             this->pSFParent->lpvtbl->fnGetAttributesOf(this->pSFParent, i,
392                                                          (LPCITEMIDLIST*)this->aPidls, &dwAttributes);
393       
394             return dwAttributes & SFGAO_CANRENAME;
395         }
396         return FALSE;
397 }
398