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