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