Sync to trunk r65566.
[reactos.git] / base / shell / rshell / CMenuSite.cpp
1 /*
2 * Shell Menu Site
3 *
4 * Copyright 2014 David Quintana
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20 #include "precomp.h"
21 #include <atlwin.h>
22 #include <shlwapi_undoc.h>
23
24 #include "CMenuSite.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(menusite);
27
28 extern "C"
29 HRESULT WINAPI CMenuSite_Constructor(REFIID riid, LPVOID *ppv)
30 {
31 return ShellObjectCreator<CMenuSite>(riid, ppv);
32 }
33
34 CMenuSite::CMenuSite() :
35 m_DeskBarSite(NULL),
36 m_BandObject(NULL),
37 m_DeskBand(NULL),
38 m_WinEventHandler(NULL),
39 m_hWndBand(NULL)
40 {
41 }
42
43 HRESULT STDMETHODCALLTYPE CMenuSite::ContextSensitiveHelp(BOOL fEnterMode)
44 {
45 return E_NOTIMPL;
46 }
47
48 HRESULT STDMETHODCALLTYPE CMenuSite::GetBandSiteInfo(BANDSITEINFO *pbsinfo)
49 {
50 return E_NOTIMPL;
51 }
52
53 HRESULT STDMETHODCALLTYPE CMenuSite::RemoveBand(DWORD dwBandID)
54 {
55 return E_NOTIMPL;
56 }
57
58 HRESULT STDMETHODCALLTYPE CMenuSite::SetBandSiteInfo(const BANDSITEINFO *pbsinfo)
59 {
60 return E_NOTIMPL;
61 }
62
63 HRESULT STDMETHODCALLTYPE CMenuSite::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
64 {
65 return E_NOTIMPL;
66 }
67
68 HRESULT STDMETHODCALLTYPE CMenuSite::SetModeDBC(DWORD dwMode)
69 {
70 return E_NOTIMPL;
71 }
72
73 HRESULT STDMETHODCALLTYPE CMenuSite::TranslateAcceleratorIO(LPMSG lpMsg)
74 {
75 return S_FALSE;
76 }
77
78 HRESULT STDMETHODCALLTYPE CMenuSite::HasFocusIO()
79 {
80 return S_FALSE;
81 }
82
83 HRESULT STDMETHODCALLTYPE CMenuSite::OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus)
84 {
85 return S_OK;
86 }
87
88 HRESULT STDMETHODCALLTYPE CMenuSite::AddBand(IUnknown * punk)
89 {
90 HRESULT hr;
91
92 #define TO_HRESULT(x) ((HRESULT)(S_OK+(x)))
93
94 CComPtr<IUnknown> pUnknown;
95
96 punk->QueryInterface(IID_PPV_ARG(IUnknown, &pUnknown));
97
98 if (pUnknown == m_BandObject)
99 return TO_HRESULT(0);
100
101 if (m_BandObject)
102 {
103 hr = IUnknown_SetSite(m_BandObject, NULL);
104 if (FAILED_UNEXPECTEDLY(hr))
105 return hr;
106 }
107
108 m_BandObject = NULL;
109 m_DeskBand = NULL;
110 m_WinEventHandler = NULL;
111 m_hWndBand = NULL;
112
113 if (!pUnknown)
114 return TO_HRESULT(0);
115
116 hr = pUnknown->QueryInterface(IID_PPV_ARG(IDeskBand, &m_DeskBand));
117 if (FAILED_UNEXPECTEDLY(hr))
118 return hr;
119
120 hr = pUnknown->QueryInterface(IID_PPV_ARG(IWinEventHandler, &m_WinEventHandler));
121 if (FAILED_UNEXPECTEDLY(hr))
122 return hr;
123
124 hr = IUnknown_SetSite(pUnknown, this->ToIUnknown());
125 if (FAILED_UNEXPECTEDLY(hr))
126 return hr;
127
128 hr = IUnknown_GetWindow(pUnknown, &m_hWndBand);
129 if (FAILED_UNEXPECTEDLY(hr))
130 return hr;
131
132 m_BandObject = pUnknown;
133
134 return TO_HRESULT(0);
135 }
136
137 HRESULT STDMETHODCALLTYPE CMenuSite::EnumBands(UINT uBand, DWORD* pdwBandID)
138 {
139 if (uBand != 0)
140 return E_FAIL;
141
142 *pdwBandID = 0;
143
144 return S_OK;
145 }
146
147 HRESULT STDMETHODCALLTYPE CMenuSite::Exec(const GUID * pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
148 {
149 return IUnknown_Exec(m_DeskBarSite, *pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
150 }
151
152 HRESULT STDMETHODCALLTYPE CMenuSite::GetBandObject(DWORD dwBandID, REFIID riid, VOID **ppv)
153 {
154 if (dwBandID != 0 || m_BandObject == NULL)
155 {
156 *ppv = NULL;
157 return E_NOINTERFACE;
158 }
159
160 return m_BandObject->QueryInterface(riid, ppv);
161 }
162
163 HRESULT STDMETHODCALLTYPE CMenuSite::GetSize(DWORD dwWhich, LPRECT prc)
164 {
165 memset(prc, 0, sizeof(*prc));
166
167 if (dwWhich != 0)
168 return S_OK;
169
170 if (m_DeskBand == NULL)
171 return S_OK;
172
173 DESKBANDINFO info = { 0 };
174 info.dwMask = DBIM_MAXSIZE;
175
176 m_DeskBand->GetBandInfo(0, 0, &info);
177
178 prc->right = info.ptMaxSize.x;
179 prc->bottom = info.ptMaxSize.y;
180
181 return S_OK;
182 }
183
184 HRESULT STDMETHODCALLTYPE CMenuSite::GetWindow(HWND *phwnd)
185 {
186 if (!IsWindow())
187 return E_FAIL;
188
189 *phwnd = m_hWnd;
190
191 return S_OK;
192 }
193
194 HRESULT STDMETHODCALLTYPE CMenuSite::IsWindowOwner(HWND hWnd)
195 {
196 if (hWnd == m_hWnd)
197 return S_OK;
198
199 if (!m_WinEventHandler)
200 return S_FALSE;
201
202 return m_WinEventHandler->IsWindowOwner(hWnd);
203 }
204
205 HRESULT STDMETHODCALLTYPE CMenuSite::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
206 {
207 if (!m_WinEventHandler)
208 return S_OK;
209
210 return m_WinEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult);
211 }
212
213 HRESULT STDMETHODCALLTYPE CMenuSite::QueryBand(DWORD dwBandID, IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName)
214 {
215 if (dwBandID != 0)
216 return E_FAIL;
217
218 if (!m_BandObject)
219 {
220 *ppstb = NULL;
221 return E_NOINTERFACE;
222 }
223
224 HRESULT hr = m_BandObject->QueryInterface(IID_PPV_ARG(IDeskBand, ppstb));
225
226 *pdwState = 1;
227
228 if (cchName > 0)
229 pszName[0] = 0;
230
231 return hr;
232 }
233
234 HRESULT STDMETHODCALLTYPE CMenuSite::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
235 {
236 *ppvObject = NULL;
237
238 if (IsEqualGUID(guidService, SID_SMenuBandBottom) ||
239 IsEqualGUID(guidService, SID_SMenuBandBottomSelected) ||
240 IsEqualGUID(guidService, SID_SMenuBandChild))
241 {
242 if (m_BandObject == NULL)
243 return E_NOINTERFACE;
244
245 return IUnknown_QueryService(m_BandObject, guidService, riid, ppvObject);
246 }
247
248 if (!m_DeskBarSite)
249 return E_NOINTERFACE;
250
251 return IUnknown_QueryService(m_DeskBarSite, guidService, riid, ppvObject);
252 }
253
254 HRESULT STDMETHODCALLTYPE CMenuSite::QueryStatus(const GUID * pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
255 {
256 if (!m_DeskBarSite)
257 return E_FAIL;
258
259 return IUnknown_QueryStatus(m_DeskBarSite, *pguidCmdGroup, cCmds, prgCmds, pCmdText);
260 }
261
262 HRESULT STDMETHODCALLTYPE CMenuSite::SetDeskBarSite(IUnknown *punkSite)
263 {
264 HRESULT hr;
265
266 CComPtr<IUnknown> protectThis(this->ToIUnknown());
267
268 if (punkSite)
269 {
270 HWND hWndSite;
271
272 m_DeskBarSite = NULL;
273
274 hr = IUnknown_GetWindow(punkSite, &hWndSite);
275
276 if (FAILED(hr) || !hWndSite)
277 return E_FAIL;
278
279 if (!m_hWnd)
280 {
281 Create(hWndSite, NULL, L"MenuSite");
282 }
283
284 m_DeskBarSite = punkSite;
285
286 return S_OK;
287 }
288
289 if (m_DeskBand)
290 {
291 m_DeskBand->CloseDW(0);
292 }
293
294 hr = IUnknown_SetSite(m_BandObject, NULL);
295
296 m_BandObject = NULL;
297 m_DeskBand = NULL;
298 m_WinEventHandler = NULL;
299 m_hWndBand = NULL;
300 m_hWnd = NULL;
301 m_DeskBarSite = NULL;
302
303 return S_OK;
304 }
305
306 HRESULT STDMETHODCALLTYPE CMenuSite::UIActivateDBC(DWORD dwState)
307 {
308 if (!m_DeskBand)
309 return S_OK;
310
311 return m_DeskBand->ShowDW(dwState != 0);
312 }
313
314 HRESULT STDMETHODCALLTYPE CMenuSite::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
315 {
316 if (lpMsg)
317 return E_FAIL;
318
319 return IUnknown_UIActivateIO(m_BandObject, fActivate, lpMsg);
320 }
321
322 BOOL CMenuSite::ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult, DWORD mapId)
323 {
324 HWND hWndTarget = NULL;
325 CComPtr<IUnknown> protectThis(this->ToIUnknown());
326
327 switch (uMsg)
328 {
329 case WM_SIZE:
330 if (m_BandObject)
331 {
332 CComPtr<IMenuPopup> pMenuPopup;
333 if (SUCCEEDED(m_BandObject->QueryInterface(IID_PPV_ARG(IMenuPopup, &pMenuPopup))))
334 {
335 RECT Rect = { 0 };
336 GetClientRect(&Rect);
337 pMenuPopup->OnPosRectChangeDB(&Rect);
338 }
339 }
340 hWndTarget = hWnd;
341 lResult = 1;
342 break;
343 case WM_NOTIFY:
344 hWndTarget = reinterpret_cast<LPNMHDR>(lParam)->hwndFrom;
345 break;
346 case WM_COMMAND:
347 hWndTarget = (HWND) lParam;
348 break;
349 default:
350 return FALSE;
351 }
352
353 if (hWndTarget && m_WinEventHandler &&
354 m_WinEventHandler->IsWindowOwner(hWndTarget) == S_OK)
355 {
356 if (SUCCEEDED(m_WinEventHandler->OnWinEvent(hWndTarget, uMsg, wParam, lParam, &lResult)))
357 return TRUE;
358 }
359
360 return FALSE;
361 }