1 /* 2 * ReactOS Explorer 3 * 4 * Copyright 2009 Andrew Hill <ash77 at domain reactos.org> 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 /* 22 This class knows how to contain base bar site in a cabinet window. 23 */ 24 25 #include "shellbars.h" 26 27 /* 28 Base bar that contains a vertical or horizontal explorer band. It also 29 provides resizing abilities. 30 */ 31 /* 32 TODO: 33 **Make base bar support resizing -- almost done (need to support integral ?) 34 Add context menu for base bar 35 Fix base bar to correctly initialize fVertical field 36 Fix base bar to correctly reposition its base bar site when resized -- done ? 37 */ 38 39 class CBaseBar : 40 public CWindowImpl<CBaseBar, CWindow, CControlWinTraits>, 41 public CComObjectRootEx<CComMultiThreadModelNoCS>, 42 public IInputObjectSite, 43 public IOleCommandTarget, 44 public IServiceProvider, 45 public IInputObject, 46 public IDeskBar, 47 public IDockingWindow, 48 public IPersistStream, 49 public IPersistStreamInit, 50 public IPersistPropertyBag, 51 public IObjectWithSite 52 { 53 private: 54 CComPtr<IUnknown> fSite; 55 CComPtr<IUnknown> fClient; 56 HWND fClientWindow; 57 bool fVertical; 58 bool fVisible; 59 int fNeededSize; // width or height 60 61 // used by resize tracking loop 62 bool fTracking; 63 POINT fLastLocation; 64 public: 65 CBaseBar(); 66 ~CBaseBar(); 67 HRESULT Initialize(BOOL); 68 69 public: 70 HRESULT ReserveBorderSpace(); 71 72 // *** IOleWindow methods *** 73 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd); 74 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); 75 76 // *** IInputObjectSite specific methods *** 77 virtual HRESULT STDMETHODCALLTYPE OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus); 78 79 // *** IOleCommandTarget specific methods *** 80 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, 81 OLECMD prgCmds[ ], OLECMDTEXT *pCmdText); 82 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, 83 DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut); 84 85 // *** IServiceProvider methods *** 86 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject); 87 88 // *** IInputObject methods *** 89 // forward the methods to the contained active bar 90 virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL fActivate, LPMSG lpMsg); 91 virtual HRESULT STDMETHODCALLTYPE HasFocusIO(); 92 virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg); 93 94 // *** IDeskBar methods *** 95 virtual HRESULT STDMETHODCALLTYPE SetClient(IUnknown *punkClient); 96 virtual HRESULT STDMETHODCALLTYPE GetClient(IUnknown **ppunkClient); 97 virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(LPRECT prc); 98 99 // *** IDockingWindow methods *** 100 virtual HRESULT STDMETHODCALLTYPE ShowDW(BOOL fShow); 101 virtual HRESULT STDMETHODCALLTYPE CloseDW(DWORD dwReserved); 102 virtual HRESULT STDMETHODCALLTYPE ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved); 103 104 // *** IObjectWithSite methods *** 105 virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite); 106 virtual HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, void **ppvSite); 107 108 // *** IPersist methods *** 109 virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID); 110 111 // *** IPersistStream methods *** 112 virtual HRESULT STDMETHODCALLTYPE IsDirty(); 113 virtual HRESULT STDMETHODCALLTYPE Load(IStream *pStm); 114 virtual HRESULT STDMETHODCALLTYPE Save(IStream *pStm, BOOL fClearDirty); 115 virtual HRESULT STDMETHODCALLTYPE GetSizeMax(ULARGE_INTEGER *pcbSize); 116 117 // *** IPersistStreamInit methods *** 118 virtual HRESULT STDMETHODCALLTYPE InitNew(); 119 120 // *** IPersistPropertyBag methods *** 121 virtual HRESULT STDMETHODCALLTYPE Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog); 122 virtual HRESULT STDMETHODCALLTYPE Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties); 123 124 // message handlers 125 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 126 LRESULT OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 127 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 128 LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 129 LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 130 LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 131 LRESULT OnCancelMode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 132 LRESULT OnCaptureChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 133 134 DECLARE_WND_CLASS_EX(_T("BaseBar"), 0, COLOR_3DFACE) 135 136 BEGIN_MSG_MAP(CBaseBar) 137 MESSAGE_HANDLER(WM_SIZE, OnSize) 138 MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) 139 MESSAGE_HANDLER(WM_NOTIFY, OnNotify) 140 MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) 141 MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) 142 MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) 143 MESSAGE_HANDLER(WM_CANCELMODE, OnCancelMode) 144 MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) 145 END_MSG_MAP() 146 147 BEGIN_COM_MAP(CBaseBar) 148 COM_INTERFACE_ENTRY2_IID(IID_IOleWindow, IOleWindow, IDockingWindow) 149 COM_INTERFACE_ENTRY_IID(IID_IInputObjectSite, IInputObjectSite) 150 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) 151 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) 152 COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject) 153 COM_INTERFACE_ENTRY_IID(IID_IDeskBar, IDeskBar) 154 COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow) 155 COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite) 156 COM_INTERFACE_ENTRY2_IID(IID_IPersist, IPersist, IPersistStream) 157 COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream) 158 COM_INTERFACE_ENTRY_IID(IID_IPersistStreamInit, IPersistStreamInit) 159 COM_INTERFACE_ENTRY_IID(IID_IPersistPropertyBag, IPersistPropertyBag) 160 END_COM_MAP() 161 }; 162 163 CBaseBar::CBaseBar() 164 { 165 fClientWindow = NULL; 166 fVertical = true; 167 fVisible = false; 168 fNeededSize = 200; 169 fTracking = false; 170 } 171 172 CBaseBar::~CBaseBar() 173 { 174 } 175 176 HRESULT CBaseBar::Initialize(BOOL vert) 177 { 178 fVertical = (vert == TRUE); 179 return S_OK; 180 } 181 182 HRESULT CBaseBar::ReserveBorderSpace() 183 { 184 CComPtr<IDockingWindowSite> dockingWindowSite; 185 RECT availableBorderSpace; 186 RECT neededBorderSpace; 187 HRESULT hResult; 188 189 hResult = fSite->QueryInterface(IID_PPV_ARG(IDockingWindowSite, &dockingWindowSite)); 190 if (FAILED_UNEXPECTEDLY(hResult)) 191 return hResult; 192 hResult = dockingWindowSite->GetBorderDW(static_cast<IDeskBar *>(this), &availableBorderSpace); 193 if (FAILED_UNEXPECTEDLY(hResult)) 194 return hResult; 195 memset(&neededBorderSpace, 0, sizeof(neededBorderSpace)); 196 if (fVisible) 197 { 198 if (fVertical) 199 neededBorderSpace.left = fNeededSize + GetSystemMetrics(SM_CXFRAME); 200 else 201 neededBorderSpace.bottom = fNeededSize + GetSystemMetrics(SM_CXFRAME); 202 } 203 hResult = dockingWindowSite->SetBorderSpaceDW(static_cast<IDeskBar *>(this), &neededBorderSpace); 204 if (FAILED_UNEXPECTEDLY(hResult)) 205 return hResult; 206 return S_OK; 207 } 208 209 // current bar size is stored in the registry under 210 // key=HKCU\Software\Microsoft\Internet Explorer\Explorer Bars 211 // value=current bar GUID 212 // result is 8 bytes of binary data, 2 longs. First is the size, second is reserved and will always be 0 213 /*HRESULT CBaseBar::StopCurrentBar() 214 { 215 CComPtr<IOleCommandTarget> commandTarget; 216 HRESULT hResult; 217 218 if (fCurrentBar.p != NULL) 219 { 220 hResult = fCurrentBar->QueryInterface(IID_IOleCommandTarget, (void **)&commandTarget); 221 hResult = commandTarget->Exec(NULL, 0x17, 0, NULL, NULL); 222 } 223 // hide the current bar 224 memcpy(&fCurrentActiveClass, &GUID_NULL, sizeof(fCurrentActiveClass)); 225 return S_OK; 226 }*/ 227 228 HRESULT STDMETHODCALLTYPE CBaseBar::GetWindow(HWND *lphwnd) 229 { 230 if (lphwnd == NULL) 231 return E_POINTER; 232 *lphwnd = m_hWnd; 233 return S_OK; 234 } 235 236 HRESULT STDMETHODCALLTYPE CBaseBar::ContextSensitiveHelp(BOOL fEnterMode) 237 { 238 return E_NOTIMPL; 239 } 240 241 HRESULT STDMETHODCALLTYPE CBaseBar::OnFocusChangeIS (IUnknown *punkObj, BOOL fSetFocus) 242 { 243 return IUnknown_OnFocusChangeIS(fSite, punkObj, fSetFocus); 244 } 245 246 HRESULT STDMETHODCALLTYPE CBaseBar::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, 247 OLECMD prgCmds[ ], OLECMDTEXT *pCmdText) 248 { 249 return E_NOTIMPL; 250 } 251 252 HRESULT STDMETHODCALLTYPE CBaseBar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, 253 DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) 254 { 255 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer)) 256 { 257 // pass through to the explorer ? 258 } 259 else if (IsEqualIID(*pguidCmdGroup, IID_IDeskBarClient)) 260 { 261 switch (nCmdID) 262 { 263 case 0: 264 { 265 // hide current band 266 ShowDW(0); 267 268 // Inform our site that we closed 269 VARIANT var; 270 V_VT(&var) = VT_UNKNOWN; 271 V_UNKNOWN(&var) = static_cast<IDeskBar *>(this); 272 IUnknown_Exec(fSite, CGID_Explorer, 0x22, 0, &var, NULL); 273 break; 274 } 275 case 2: 276 // switch bands 277 break; 278 case 3: 279 break; 280 } 281 } 282 return E_NOTIMPL; 283 } 284 285 HRESULT STDMETHODCALLTYPE CBaseBar::QueryService(REFGUID guidService, REFIID riid, void **ppvObject) 286 { 287 CComPtr<IServiceProvider> serviceProvider; 288 HRESULT hResult; 289 290 if (fSite == NULL) 291 return E_FAIL; 292 hResult = fSite->QueryInterface(IID_PPV_ARG(IServiceProvider, &serviceProvider)); 293 if (FAILED_UNEXPECTEDLY(hResult)) 294 return hResult; 295 // called for SID_STopLevelBrowser, IID_IBrowserService to find top level browser 296 // called for SID_IWebBrowserApp, IID_IConnectionPointContainer 297 // connection point called for DIID_DWebBrowserEvents2 to establish connection 298 return serviceProvider->QueryService(guidService, riid, ppvObject); 299 } 300 301 HRESULT STDMETHODCALLTYPE CBaseBar::UIActivateIO(BOOL fActivate, LPMSG lpMsg) 302 { 303 return IUnknown_UIActivateIO(fClient, fActivate, lpMsg); 304 } 305 306 HRESULT STDMETHODCALLTYPE CBaseBar::HasFocusIO() 307 { 308 return IUnknown_HasFocusIO(fClient); 309 } 310 311 HRESULT STDMETHODCALLTYPE CBaseBar::TranslateAcceleratorIO(LPMSG lpMsg) 312 { 313 return IUnknown_TranslateAcceleratorIO(fClient, lpMsg); 314 } 315 316 HRESULT STDMETHODCALLTYPE CBaseBar::SetClient(IUnknown *punkClient) 317 { 318 CComPtr<IOleWindow> oleWindow; 319 HWND ownerWindow; 320 HRESULT hResult; 321 322 /* Clean up old client */ 323 fClient = NULL; 324 325 if (punkClient) 326 { 327 hResult = punkClient->QueryInterface(IID_PPV_ARG(IUnknown, &fClient)); 328 if (FAILED_UNEXPECTEDLY(hResult)) 329 return hResult; 330 hResult = fSite->QueryInterface(IID_PPV_ARG(IOleWindow, &oleWindow)); 331 if (FAILED_UNEXPECTEDLY(hResult)) 332 return hResult; 333 hResult = oleWindow->GetWindow(&ownerWindow); 334 if (FAILED_UNEXPECTEDLY(hResult)) 335 return hResult; 336 Create(ownerWindow, 0, NULL, 337 WS_VISIBLE | WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_TOOLWINDOW); 338 ReserveBorderSpace(); 339 } 340 else 341 { 342 DestroyWindow(); 343 } 344 return S_OK; 345 } 346 347 HRESULT STDMETHODCALLTYPE CBaseBar::GetClient(IUnknown **ppunkClient) 348 { 349 if (ppunkClient == NULL) 350 return E_POINTER; 351 *ppunkClient = fClient; 352 if (fClient.p != NULL) 353 fClient.p->AddRef(); 354 return S_OK; 355 } 356 357 HRESULT STDMETHODCALLTYPE CBaseBar::OnPosRectChangeDB(LPRECT prc) 358 { 359 if (prc == NULL) 360 return E_POINTER; 361 if (fVertical) 362 fNeededSize = prc->right - prc->left; 363 else 364 fNeededSize = prc->bottom - prc->top; 365 ReserveBorderSpace(); 366 return S_OK; 367 } 368 369 HRESULT STDMETHODCALLTYPE CBaseBar::ShowDW(BOOL fShow) 370 { 371 fVisible = fShow ? true : false; 372 ShowWindow(fShow); 373 ReserveBorderSpace(); 374 return S_OK; 375 } 376 377 HRESULT STDMETHODCALLTYPE CBaseBar::CloseDW(DWORD dwReserved) 378 { 379 ShowDW(0); 380 // Detach from our client 381 SetClient(NULL); 382 // Destroy our site 383 SetSite(NULL); 384 return S_OK; 385 } 386 387 HRESULT STDMETHODCALLTYPE CBaseBar::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved) 388 { 389 ReserveBorderSpace(); 390 return S_OK; 391 } 392 393 HRESULT STDMETHODCALLTYPE CBaseBar::SetSite(IUnknown *pUnkSite) 394 { 395 fSite = pUnkSite; 396 return S_OK; 397 } 398 399 HRESULT STDMETHODCALLTYPE CBaseBar::GetSite(REFIID riid, void **ppvSite) 400 { 401 if (ppvSite == NULL) 402 return E_POINTER; 403 *ppvSite = fSite; 404 if (fSite.p != NULL) 405 fSite.p->AddRef(); 406 return S_OK; 407 } 408 409 HRESULT STDMETHODCALLTYPE CBaseBar::GetClassID(CLSID *pClassID) 410 { 411 if (pClassID == NULL) 412 return E_POINTER; 413 // TODO: what class to return here? 414 return E_NOTIMPL; 415 } 416 417 HRESULT STDMETHODCALLTYPE CBaseBar::IsDirty() 418 { 419 return E_NOTIMPL; 420 } 421 422 HRESULT STDMETHODCALLTYPE CBaseBar::Load(IStream *pStm) 423 { 424 return E_NOTIMPL; 425 } 426 427 HRESULT STDMETHODCALLTYPE CBaseBar::Save(IStream *pStm, BOOL fClearDirty) 428 { 429 return E_NOTIMPL; 430 } 431 432 HRESULT STDMETHODCALLTYPE CBaseBar::GetSizeMax(ULARGE_INTEGER *pcbSize) 433 { 434 if (pcbSize == NULL) 435 return E_POINTER; 436 return E_NOTIMPL; 437 } 438 439 HRESULT STDMETHODCALLTYPE CBaseBar::InitNew() 440 { 441 return E_NOTIMPL; 442 } 443 444 HRESULT STDMETHODCALLTYPE CBaseBar::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog) 445 { 446 return E_NOTIMPL; 447 } 448 449 HRESULT STDMETHODCALLTYPE CBaseBar::Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties) 450 { 451 return E_NOTIMPL; 452 } 453 454 LRESULT CBaseBar::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 455 { 456 DWORD dwWidth; 457 DWORD dwHeight; 458 CComPtr<IOleWindow> pClient; 459 HWND clientHwnd; 460 HRESULT hr; 461 462 if (fVisible) 463 { 464 dwWidth = LOWORD(lParam); 465 dwHeight = HIWORD(lParam); 466 467 // substract resizing grips to child's window size 468 if (fVertical) 469 dwWidth -= GetSystemMetrics(SM_CXFRAME); 470 else 471 dwHeight -= GetSystemMetrics(SM_CXFRAME); 472 hr = fClient->QueryInterface(IID_PPV_ARG(IOleWindow, &pClient)); 473 if (FAILED_UNEXPECTEDLY(hr)) 474 return 0; 475 hr = pClient->GetWindow(&clientHwnd); 476 if (FAILED_UNEXPECTEDLY(hr)) 477 return 0; 478 ::SetWindowPos(clientHwnd, NULL, 0, (fVertical) ? 0 : GetSystemMetrics(SM_CXFRAME), dwWidth, dwHeight, NULL); 479 bHandled = TRUE; 480 } 481 return 0; 482 } 483 484 LRESULT CBaseBar::OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 485 { 486 if ((short)lParam != HTCLIENT || (HWND)wParam != m_hWnd) 487 { 488 bHandled = FALSE; 489 return 0; 490 } 491 if (fVertical) 492 SetCursor(LoadCursor(NULL, IDC_SIZEWE)); 493 else 494 SetCursor(LoadCursor(NULL, IDC_SIZENS)); 495 return 1; 496 } 497 498 LRESULT CBaseBar::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 499 { 500 CComPtr<IWinEventHandler> winEventHandler; 501 LRESULT result; 502 HRESULT hResult; 503 504 result = 0; 505 if (fClient.p != NULL) 506 { 507 hResult = fClient->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler)); 508 if (SUCCEEDED(hResult) && winEventHandler.p != NULL) 509 hResult = winEventHandler->OnWinEvent(NULL, uMsg, wParam, lParam, &result); 510 } 511 return result; 512 } 513 514 LRESULT CBaseBar::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 515 { 516 SetCapture(); 517 fTracking = true; 518 fLastLocation.x = (short)LOWORD(lParam); 519 fLastLocation.y = (short)HIWORD(lParam); 520 return 0; 521 } 522 523 LRESULT CBaseBar::OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 524 { 525 ReleaseCapture(); 526 fTracking = false; 527 return 0; 528 } 529 530 LRESULT CBaseBar::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 531 { 532 POINT newLocation; 533 int delta; 534 535 if (fTracking) 536 { 537 newLocation.x = (short)LOWORD(lParam); 538 newLocation.y = (short)HIWORD(lParam); 539 if (fVertical) 540 delta = newLocation.x - fLastLocation.x; 541 else 542 delta = fLastLocation.y - newLocation.y; 543 if (fNeededSize + delta < 0) 544 return 0; 545 fNeededSize += delta; 546 fLastLocation = newLocation; 547 ReserveBorderSpace(); 548 } 549 return 0; 550 } 551 552 LRESULT CBaseBar::OnCancelMode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 553 { 554 fTracking = false; 555 return 0; 556 } 557 558 LRESULT CBaseBar::OnCaptureChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 559 { 560 fTracking = false; 561 return 0; 562 } 563 564 HRESULT CBaseBar_CreateInstance(REFIID riid, void **ppv, BOOL vertical) 565 { 566 return ShellObjectCreatorInit<CBaseBar, BOOL>(vertical, riid, ppv); 567 } 568