3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/shell32/CDefViewBckgrndMenu.cpp
5 * PURPOSE: background context menu of the CDefView
6 * PROGRAMMERS: Giannis Adamopoulos
11 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
13 class CDefViewBckgrndMenu
:
14 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
16 public IObjectWithSite
19 CComPtr
<IUnknown
> m_site
;
20 CComPtr
<IShellFolder
> m_psf
;
21 CComPtr
<IContextMenu
> m_folderCM
;
24 UINT m_LastFolderCMId
;
26 BOOL
_bIsDesktopBrowserMenu();
29 CDefViewBckgrndMenu();
30 ~CDefViewBckgrndMenu();
31 HRESULT
Initialize(IShellFolder
* psf
);
34 virtual HRESULT WINAPI
QueryContextMenu(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
);
35 virtual HRESULT WINAPI
InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
);
36 virtual HRESULT WINAPI
GetCommandString(UINT_PTR idCommand
, UINT uFlags
, UINT
*lpReserved
, LPSTR lpszName
, UINT uMaxNameLen
);
39 virtual HRESULT WINAPI
HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
42 virtual HRESULT WINAPI
HandleMenuMsg2(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*plResult
);
45 virtual HRESULT STDMETHODCALLTYPE
SetSite(IUnknown
*pUnkSite
);
46 virtual HRESULT STDMETHODCALLTYPE
GetSite(REFIID riid
, void **ppvSite
);
48 BEGIN_COM_MAP(CDefViewBckgrndMenu
)
49 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
50 COM_INTERFACE_ENTRY_IID(IID_IContextMenu2
, IContextMenu2
)
51 COM_INTERFACE_ENTRY_IID(IID_IContextMenu3
, IContextMenu3
)
52 COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite
, IObjectWithSite
)
56 CDefViewBckgrndMenu::CDefViewBckgrndMenu()
62 CDefViewBckgrndMenu::~CDefViewBckgrndMenu()
66 BOOL
CDefViewBckgrndMenu::_bIsDesktopBrowserMenu()
71 /* Get a pointer to the shell browser */
72 CComPtr
<IShellView
> psv
;
73 HRESULT hr
= IUnknown_QueryService(m_site
, SID_IFolderView
, IID_PPV_ARG(IShellView
, &psv
));
74 if (FAILED_UNEXPECTEDLY(hr
))
77 FOLDERSETTINGS FolderSettings
;
78 hr
= psv
->GetCurrentInfo(&FolderSettings
);
79 if (FAILED_UNEXPECTEDLY(hr
))
82 return ((FolderSettings
.fFlags
& FWF_DESKTOP
) == FWF_DESKTOP
);
85 BOOL
CDefViewBckgrndMenu::_bCanPaste()
87 /* If the folder doesn't have a drop target we can't paste */
88 CComPtr
<IDropTarget
> pdt
;
89 HRESULT hr
= m_psf
->CreateViewObject(NULL
, IID_PPV_ARG(IDropTarget
, &pdt
));
93 /* We can only paste if CFSTR_SHELLIDLIST is present in the clipboard */
94 CComPtr
<IDataObject
> pDataObj
;
95 hr
= OleGetClipboard(&pDataObj
);
102 /* Set the FORMATETC structure*/
103 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
104 hr
= pDataObj
->GetData(&formatetc
, &medium
);
108 ReleaseStgMedium(&medium
);
113 CDefViewBckgrndMenu::Initialize(IShellFolder
* psf
)
117 /* Get the context menu of the folder. Do it here because someone may call
118 InvokeCommand without calling QueryContextMenu. It is fine if this fails */
119 m_psf
->CreateViewObject(NULL
, IID_PPV_ARG(IContextMenu
, &m_folderCM
));
126 CDefViewBckgrndMenu::SetSite(IUnknown
*pUnkSite
)
131 IUnknown_SetSite(m_folderCM
, pUnkSite
);
138 CDefViewBckgrndMenu::GetSite(REFIID riid
, void **ppvSite
)
143 return m_site
->QueryInterface(riid
, ppvSite
);
148 CDefViewBckgrndMenu::QueryContextMenu(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
)
154 /* This is something the implementations of IContextMenu should never really do.
155 However CDefViewBckgrndMenu is more or less an overengineering result, its code could really be part of the
156 CDefView. Given this, I think that abusing the interface here is not that bad since only CDefView is the ony
157 user of this class. Here we need to do two things to keep things as simple as possible.
158 First we want the menu part added by the shell folder to be the first to add so as to make as few id translations
159 as possible. Second, we want to add the default part of the background menu without shifted ids, so as
160 to let the CDefView fill some parts like filling the arrange modes or checking the view mode. In order
161 for that to work we need to save idCmdFirst because our caller will pass id offsets to InvokeCommand.
162 This makes it impossible to concatenate the CDefViewBckgrndMenu with other menus since it abuses IContextMenu
163 but as stated above, its sole user is CDefView and should really be that way. */
164 m_idCmdFirst
= idCmdFirst
;
166 /* Let the shell folder add any items it wants to add in the background context menu */
169 hr
= m_folderCM
->QueryContextMenu(hMenu
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
172 m_LastFolderCMId
= LOWORD(hr
);
173 cIds
= m_LastFolderCMId
;
177 WARN("QueryContextMenu failed!\n");
182 WARN("GetUIObjectOf didn't give any context menu!\n");
185 /* Load the default part of the background context menu */
186 hMenuPart
= LoadMenuW(shell32_hInstance
, L
"MENU_002");
189 /* Don't show the view submenu for the desktop */
190 if (_bIsDesktopBrowserMenu())
192 DeleteMenu(hMenuPart
, FCIDM_SHVIEW_VIEW
, MF_BYCOMMAND
);
195 /* Disable the paste options if it is not possible */
198 EnableMenuItem(hMenuPart
, FCIDM_SHVIEW_INSERT
, MF_BYCOMMAND
| MF_GRAYED
);
199 EnableMenuItem(hMenuPart
, FCIDM_SHVIEW_INSERTLINK
, MF_BYCOMMAND
| MF_GRAYED
);
202 /* merge general background context menu in */
203 Shell_MergeMenus(hMenu
, GetSubMenu(hMenuPart
, 0), indexMenu
, 0, idCmdLast
, MM_DONTREMOVESEPS
| MM_SUBMENUSHAVEIDS
| MM_ADDSEPARATOR
);
204 DestroyMenu(hMenuPart
);
208 ERR("Failed to load menu from resource!\n");
211 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, cIds
);
216 CDefViewBckgrndMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
)
218 UINT idCmd
= LOWORD(lpcmi
->lpVerb
);
220 if (HIWORD(lpcmi
->lpVerb
) && !strcmp(lpcmi
->lpVerb
, CMDSTR_VIEWLISTA
))
222 idCmd
= FCIDM_SHVIEW_LISTVIEW
;
224 else if (HIWORD(lpcmi
->lpVerb
) && !strcmp(lpcmi
->lpVerb
, CMDSTR_VIEWDETAILSA
))
226 idCmd
= FCIDM_SHVIEW_REPORTVIEW
;
228 else if(HIWORD(lpcmi
->lpVerb
) != 0 || idCmd
< m_LastFolderCMId
)
232 return m_folderCM
->InvokeCommand(lpcmi
);
234 WARN("m_folderCM is NULL!\n");
239 /* The default part of the background menu doesn't have shifted ids so we need to convert the id offset to the real id */
240 idCmd
+= m_idCmdFirst
;
243 /* The commands that are handled by the def view are forwarded to it */
246 case FCIDM_SHVIEW_INSERT
:
247 case FCIDM_SHVIEW_INSERTLINK
:
250 lpcmi
->lpVerb
= MAKEINTRESOURCEA(idCmd
);
251 return m_folderCM
->InvokeCommand(lpcmi
);
253 WARN("m_folderCM is NULL!\n");
255 case FCIDM_SHVIEW_BIGICON
:
256 case FCIDM_SHVIEW_SMALLICON
:
257 case FCIDM_SHVIEW_LISTVIEW
:
258 case FCIDM_SHVIEW_REPORTVIEW
:
259 case 0x30: /* FIX IDS in resource files */
263 case FCIDM_SHVIEW_AUTOARRANGE
:
264 case FCIDM_SHVIEW_SNAPTOGRID
:
265 case FCIDM_SHVIEW_REFRESH
:
269 /* Get a pointer to the shell browser */
270 CComPtr
<IShellView
> psv
;
271 HRESULT hr
= IUnknown_QueryService(m_site
, SID_IFolderView
, IID_PPV_ARG(IShellView
, &psv
));
272 if (FAILED_UNEXPECTEDLY(hr
))
276 if (SUCCEEDED(psv
->GetWindow(&hwndSV
)))
277 SendMessageW(hwndSV
, WM_COMMAND
, MAKEWPARAM(idCmd
, 0), 0);
281 ERR("Got unknown command id %ul\n", LOWORD(lpcmi
->lpVerb
));
287 CDefViewBckgrndMenu::GetCommandString(UINT_PTR idCommand
, UINT uFlags
, UINT
*lpReserved
, LPSTR lpszName
, UINT uMaxNameLen
)
291 return m_folderCM
->GetCommandString(idCommand
, uFlags
, lpReserved
, lpszName
, uMaxNameLen
);
299 CDefViewBckgrndMenu::HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
303 CComPtr
<IContextMenu2
> pfolderCM2
;
304 HRESULT hr
= m_folderCM
->QueryInterface(IID_PPV_ARG(IContextMenu2
, &pfolderCM2
));
305 if (FAILED_UNEXPECTEDLY(hr
))
308 return pfolderCM2
->HandleMenuMsg(uMsg
, wParam
, lParam
);
316 CDefViewBckgrndMenu::HandleMenuMsg2(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*plResult
)
320 CComPtr
<IContextMenu3
> pfolderCM3
;
321 HRESULT hr
= m_folderCM
->QueryInterface(IID_PPV_ARG(IContextMenu3
, &pfolderCM3
));
322 if (FAILED_UNEXPECTEDLY(hr
))
325 return pfolderCM3
->HandleMenuMsg2(uMsg
, wParam
, lParam
, plResult
);
333 CDefViewBckgrndMenu_CreateInstance(IShellFolder
* psf
, REFIID riid
, void **ppv
)
335 return ShellObjectCreatorInit
<CDefViewBckgrndMenu
>(psf
, riid
, ppv
);