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
)
121 CDefViewBckgrndMenu::SetSite(IUnknown
*pUnkSite
)
129 CDefViewBckgrndMenu::GetSite(REFIID riid
, void **ppvSite
)
134 return m_site
->QueryInterface(riid
, ppvSite
);
139 CDefViewBckgrndMenu::QueryContextMenu(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
)
145 /* This is something the implementations of IContextMenu should never really do.
146 However CDefViewBckgrndMenu is more or less an overengineering result, its code could really be part of the
147 CDefView. Given this, I think that abusing the interface here is not that bad since only CDefView is the ony
148 user of this class. Here we need to do two things to keep things as simple as possible.
149 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
150 as possible. Second, we want to add the default part of the background menu without shifted ids, so as
151 to let the CDefView fill some parts like filling the arrange modes or checking the view mode. In order
152 for that to work we need to save idCmdFirst because our caller will pass id offsets to InvokeCommand.
153 This makes it impossible to concatenate the CDefViewBckgrndMenu with other menus since it abuses IContextMenu
154 but as stated above, its sole user is CDefView and should really be that way. */
155 m_idCmdFirst
= idCmdFirst
;
157 /* Query the shell folder to add any items it wants to add in the background context menu */
158 hr
= m_psf
->CreateViewObject(NULL
, IID_PPV_ARG(IContextMenu
, &m_folderCM
));
161 hr
= m_folderCM
->QueryContextMenu(hMenu
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
164 m_LastFolderCMId
= LOWORD(hr
);
165 cIds
= m_LastFolderCMId
;
169 WARN("QueryContextMenu failed!\n");
174 WARN("GetUIObjectOf didn't give any context menu!\n");
177 /* Load the default part of the background context menu */
178 hMenuPart
= LoadMenuW(shell32_hInstance
, L
"MENU_002");
181 /* Don't show the view submenu for the desktop */
182 if (_bIsDesktopBrowserMenu())
184 DeleteMenu(hMenuPart
, FCIDM_SHVIEW_VIEW
, MF_BYCOMMAND
);
187 /* Disable the paste options if it is not possible */
190 EnableMenuItem(hMenuPart
, FCIDM_SHVIEW_INSERT
, MF_BYCOMMAND
| MF_GRAYED
);
191 EnableMenuItem(hMenuPart
, FCIDM_SHVIEW_INSERTLINK
, MF_BYCOMMAND
| MF_GRAYED
);
194 /* merge general background context menu in */
195 Shell_MergeMenus(hMenu
, GetSubMenu(hMenuPart
, 0), indexMenu
, 0, idCmdLast
, MM_DONTREMOVESEPS
| MM_SUBMENUSHAVEIDS
| MM_ADDSEPARATOR
);
196 DestroyMenu(hMenuPart
);
200 ERR("Failed to load menu from resource!\n");
203 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, cIds
);
208 CDefViewBckgrndMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
)
210 UINT idCmd
= LOWORD(lpcmi
->lpVerb
);
211 if(HIWORD(lpcmi
->lpVerb
) != 0 || idCmd
< m_LastFolderCMId
)
213 return m_folderCM
->InvokeCommand(lpcmi
);
216 /* The default part of the background menu doesn't have shifted ids so we need to convert the id offset to the real id */
217 idCmd
+= m_idCmdFirst
;
219 /* The commands that are handled by the def view are forwarded to it */
222 case FCIDM_SHVIEW_INSERT
:
223 case FCIDM_SHVIEW_INSERTLINK
:
224 lpcmi
->lpVerb
= MAKEINTRESOURCEA(idCmd
);
225 return m_folderCM
->InvokeCommand(lpcmi
);
226 case FCIDM_SHVIEW_BIGICON
:
227 case FCIDM_SHVIEW_SMALLICON
:
228 case FCIDM_SHVIEW_LISTVIEW
:
229 case FCIDM_SHVIEW_REPORTVIEW
:
230 case 0x30: /* FIX IDS in resource files */
234 case FCIDM_SHVIEW_AUTOARRANGE
:
235 case FCIDM_SHVIEW_SNAPTOGRID
:
236 case FCIDM_SHVIEW_REFRESH
:
240 /* Get a pointer to the shell browser */
241 CComPtr
<IShellView
> psv
;
242 HRESULT hr
= IUnknown_QueryService(m_site
, SID_IFolderView
, IID_PPV_ARG(IShellView
, &psv
));
243 if (FAILED_UNEXPECTEDLY(hr
))
247 if (SUCCEEDED(psv
->GetWindow(&hwndSV
)))
248 SendMessageW(hwndSV
, WM_COMMAND
, MAKEWPARAM(idCmd
, 0), 0);
252 ERR("Got unknown command id %ul\n", LOWORD(lpcmi
->lpVerb
));
258 CDefViewBckgrndMenu::GetCommandString(UINT_PTR idCommand
, UINT uFlags
, UINT
*lpReserved
, LPSTR lpszName
, UINT uMaxNameLen
)
262 return m_folderCM
->GetCommandString(idCommand
, uFlags
, lpReserved
, lpszName
, uMaxNameLen
);
270 CDefViewBckgrndMenu::HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
274 CComPtr
<IContextMenu2
> pfolderCM2
;
275 HRESULT hr
= m_folderCM
->QueryInterface(IID_PPV_ARG(IContextMenu2
, &pfolderCM2
));
276 if (FAILED_UNEXPECTEDLY(hr
))
279 return pfolderCM2
->HandleMenuMsg(uMsg
, wParam
, lParam
);
287 CDefViewBckgrndMenu::HandleMenuMsg2(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*plResult
)
291 CComPtr
<IContextMenu3
> pfolderCM3
;
292 HRESULT hr
= m_folderCM
->QueryInterface(IID_PPV_ARG(IContextMenu3
, &pfolderCM3
));
293 if (FAILED_UNEXPECTEDLY(hr
))
296 return pfolderCM3
->HandleMenuMsg2(uMsg
, wParam
, lParam
, plResult
);
304 CDefViewBckgrndMenu_CreateInstance(IShellFolder
* psf
, REFIID riid
, void **ppv
)
306 return ShellObjectCreatorInit
<CDefViewBckgrndMenu
>(psf
, riid
, ppv
);