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 Base bar that contains a vertical or horizontal explorer band. It also
23 provides resizing abilities.
24 */
25
26 #include "precomp.h"
27
28 /*
29 TODO:
30 ****When a new bar is added, resize correctly the band inside instead of keeping current size.
31 *Translate close button label
32 **Add owner draw for base bar -- hackplemented atm
33 **Make label text in base bar always draw in black
34 ***Set rebar band style flags accordingly to what band object asked.
35 ***Set rebar style accordingly to direction
36 ****This class should also manage desktop bands ? (another kind of explorer bands)
37 */
38
39 class CBaseBarSite :
40 public CWindowImpl<CBaseBarSite, CWindow, CControlWinTraits>,
41 public CComObjectRootEx<CComMultiThreadModelNoCS>,
42 // public IDockingWindowSite,
43 public IInputObject,
44 public IServiceProvider,
45 public IWinEventHandler,
46 public IInputObjectSite,
47 public IDeskBarClient,
48 public IOleCommandTarget,
49 public IBandSite,
50 // public IBandSiteHelper,
51 // public IExplorerToolbar,
52 public IPersistStream
53 {
54 private:
55 class CBarInfo
56 {
57 public:
58 CComPtr<IUnknown> fTheBar;
59 CLSID fBarClass; // class of active bar
60 DWORD fBandID;
61
62 };
63 CBarInfo *fCurrentActiveBar; //
64 // HWND fRebarWindow; // rebar for top of window
65 CComPtr<IUnknown> fDeskBarSite;
66 DWORD fNextBandID;
67 HWND toolbarWnd;
68 HIMAGELIST toolImageList;
69 BOOL fVertical;
70 public:
71 CBaseBarSite();
72 ~CBaseBarSite();
Initialize(BOOL vert)73 HRESULT Initialize(BOOL vert) { fVertical = vert; return S_OK; };
74 private:
75 HRESULT InsertBar(IUnknown *newBar);
76
77 // *** IOleWindow methods ***
78 STDMETHOD(GetWindow)(HWND *lphwnd) override;
79 STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode) override;
80
81 // *** IInputObject methods ***
82 STDMETHOD(UIActivateIO)(BOOL fActivate, LPMSG lpMsg) override;
83 STDMETHOD(HasFocusIO)() override;
84 STDMETHOD(TranslateAcceleratorIO)(LPMSG lpMsg) override;
85
86 // *** IServiceProvider methods ***
87 STDMETHOD(QueryService)(REFGUID guidService, REFIID riid, void **ppvObject) override;
88
89 // *** IWinEventHandler methods ***
90 STDMETHOD(OnWinEvent)(
91 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult) override;
92 STDMETHOD(IsWindowOwner)(HWND hWnd) override;
93
94 // *** IInputObjectSite specific methods ***
95 STDMETHOD(OnFocusChangeIS)(IUnknown *punkObj, BOOL fSetFocus) override;
96
97 // *** IDeskBarClient methods ***
98 STDMETHOD(SetDeskBarSite)(IUnknown *punkSite) override;
99 STDMETHOD(SetModeDBC)(DWORD dwMode) override;
100 STDMETHOD(UIActivateDBC)(DWORD dwState) override;
101 STDMETHOD(GetSize)(DWORD dwWhich, LPRECT prc) override;
102
103 // *** IOleCommandTarget methods ***
104 STDMETHOD(QueryStatus)(const GUID *pguidCmdGroup, ULONG cCmds,
105 OLECMD prgCmds[ ], OLECMDTEXT *pCmdText) override;
106 STDMETHOD(Exec)(const GUID *pguidCmdGroup, DWORD nCmdID,
107 DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) override;
108
109 // *** IBandSite specific methods ***
110 STDMETHOD(AddBand)(IUnknown *punk) override;
111 STDMETHOD(EnumBands)(UINT uBand, DWORD *pdwBandID) override;
112 STDMETHOD(QueryBand)(DWORD dwBandID, IDeskBand **ppstb, DWORD *pdwState,
113 LPWSTR pszName, int cchName) override;
114 STDMETHOD(SetBandState)(DWORD dwBandID, DWORD dwMask, DWORD dwState) override;
115 STDMETHOD(RemoveBand)(DWORD dwBandID) override;
116 STDMETHOD(GetBandObject)(DWORD dwBandID, REFIID riid, void **ppv) override;
117 STDMETHOD(SetBandSiteInfo)(const BANDSITEINFO *pbsinfo) override;
118 STDMETHOD(GetBandSiteInfo)(BANDSITEINFO *pbsinfo) override;
119
120 // *** IPersist methods ***
121 STDMETHOD(GetClassID)(CLSID *pClassID) override;
122
123 // *** IPersistStream methods ***
124 STDMETHOD(IsDirty)() override;
125 STDMETHOD(Load)(IStream *pStm) override;
126 STDMETHOD(Save)(IStream *pStm, BOOL fClearDirty) override;
127 STDMETHOD(GetSizeMax)(ULARGE_INTEGER *pcbSize) override;
128
129 // message handlers
130 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
131 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
132 LRESULT OnCustomDraw(LPNMCUSTOMDRAW pnmcd);
133
134 // Helper functions
135 HFONT GetTitleFont();
136 HRESULT FindBandByGUID(REFIID pGuid, DWORD *pdwBandID);
137 HRESULT ShowBand(DWORD dwBandID);
138 HRESULT GetInternalBandInfo(UINT uBand, REBARBANDINFO *pBandInfo);
139 HRESULT GetInternalBandInfo(UINT uBand, REBARBANDINFO *pBandInfo, DWORD fMask);
140
141
142 BEGIN_MSG_MAP(CBaseBarSite)
143 MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
144 MESSAGE_HANDLER(WM_COMMAND, OnCommand)
145 END_MSG_MAP()
146
147 BEGIN_COM_MAP(CBaseBarSite)
148 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
149 // COM_INTERFACE_ENTRY_IID(IID_IDockingWindowSite, IDockingWindowSite)
150 COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject)
151 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
152 COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler)
153 COM_INTERFACE_ENTRY_IID(IID_IInputObjectSite, IInputObjectSite)
154 COM_INTERFACE_ENTRY_IID(IID_IDeskBarClient, IDeskBarClient)
155 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
156 COM_INTERFACE_ENTRY_IID(IID_IBandSite, IBandSite)
157 // COM_INTERFACE_ENTRY_IID(IID_IBandSiteHelper, IBandSiteHelper)
158 // COM_INTERFACE_ENTRY_IID(IID_IExplorerToolbar, IExplorerToolbar)
159 COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
160 COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream)
161 END_COM_MAP()
162 };
163
CBaseBarSite()164 CBaseBarSite::CBaseBarSite() : fVertical(TRUE)
165 {
166 fCurrentActiveBar = NULL;
167 fNextBandID = 1;
168 }
169
~CBaseBarSite()170 CBaseBarSite::~CBaseBarSite()
171 {
172 TRACE("CBaseBarSite deleted\n");
173 }
174
InsertBar(IUnknown * newBar)175 HRESULT CBaseBarSite::InsertBar(IUnknown *newBar)
176 {
177 CComPtr<IPersist> persist;
178 CComPtr<IObjectWithSite> site;
179 CComPtr<IOleWindow> oleWindow;
180 CComPtr<IDeskBand> deskBand;
181 CBarInfo *newInfo;
182 REBARBANDINFOW bandInfo;
183 DESKBANDINFO deskBandInfo;
184 DWORD thisBandID;
185 HRESULT hResult;
186 CLSID tmp;
187
188 hResult = newBar->QueryInterface(IID_PPV_ARG(IPersist, &persist));
189 if (FAILED_UNEXPECTEDLY(hResult))
190 return hResult;
191 hResult = newBar->QueryInterface(IID_PPV_ARG(IObjectWithSite, &site));
192 if (FAILED_UNEXPECTEDLY(hResult))
193 return hResult;
194 hResult = newBar->QueryInterface(IID_PPV_ARG(IOleWindow, &oleWindow));
195 if (FAILED_UNEXPECTEDLY(hResult))
196 return hResult;
197 hResult = newBar->QueryInterface(IID_PPV_ARG(IDeskBand, &deskBand));
198 if (FAILED_UNEXPECTEDLY(hResult))
199 return hResult;
200
201 // Check if the GUID already exists
202 hResult = persist->GetClassID(&tmp);
203 if (!SUCCEEDED(hResult))
204 {
205 return E_INVALIDARG;
206 }
207 if (FindBandByGUID(tmp, &thisBandID) == S_OK)
208 {
209 return ShowBand(thisBandID);
210 }
211
212 hResult = site->SetSite(static_cast<IOleWindow *>(this));
213 if (FAILED_UNEXPECTEDLY(hResult))
214 return hResult;
215
216 ATLTRY(newInfo = new CBarInfo);
217 if (newInfo == NULL)
218 return E_OUTOFMEMORY;
219
220 // set new bar info
221 thisBandID = fNextBandID++;
222 newInfo->fTheBar = newBar;
223 newInfo->fBandID = thisBandID;
224 newInfo->fBarClass = tmp;
225
226 // get band info
227 deskBandInfo.dwMask = DBIM_MINSIZE | DBIM_ACTUAL | DBIM_TITLE | DBIM_BKCOLOR;
228 deskBandInfo.wszTitle[0] = 0;
229 hResult = deskBand->GetBandInfo(0, (fVertical) ? DBIF_VIEWMODE_VERTICAL : DBIF_VIEWMODE_NORMAL, &deskBandInfo);
230
231 // insert band
232 memset(&bandInfo, 0, sizeof(bandInfo));
233 bandInfo.cbSize = sizeof(bandInfo);
234 bandInfo.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_TEXT |
235 RBBIM_LPARAM | RBBIM_ID;
236 bandInfo.fStyle = RBBS_TOPALIGN | RBBS_VARIABLEHEIGHT | RBBS_NOGRIPPER;
237 bandInfo.lpText = deskBandInfo.wszTitle;
238 hResult = oleWindow->GetWindow(&bandInfo.hwndChild);
239 /* It seems Windows XP doesn't take account of band minsize */
240 #if 0
241 bandInfo.cxMinChild = 200; //deskBandInfo.ptMinSize.x;
242 bandInfo.cyMinChild = 200; //deskBandInfo.ptMinSize.y;
243 #endif
244 bandInfo.cx = 0;
245 bandInfo.wID = thisBandID;
246 bandInfo.cyChild = -1; //deskBandInfo.ptActual.y;
247 bandInfo.cyMaxChild = 32000;
248 bandInfo.cyIntegral = 1;
249 bandInfo.cxIdeal = 0; //deskBandInfo.ptActual.x;
250 bandInfo.lParam = reinterpret_cast<LPARAM>(newInfo);
251 SendMessage(RB_INSERTBANDW, -1, reinterpret_cast<LPARAM>(&bandInfo));
252 hResult = ShowBand(newInfo->fBandID);
253 //fCurrentActiveBar = newInfo;
254 return hResult;
255 }
256
GetWindow(HWND * lphwnd)257 HRESULT STDMETHODCALLTYPE CBaseBarSite::GetWindow(HWND *lphwnd)
258 {
259 if (lphwnd == NULL)
260 return E_POINTER;
261 *lphwnd = m_hWnd;
262 return S_OK;
263 }
264
ContextSensitiveHelp(BOOL fEnterMode)265 HRESULT STDMETHODCALLTYPE CBaseBarSite::ContextSensitiveHelp(BOOL fEnterMode)
266 {
267 return E_NOTIMPL;
268 }
269
UIActivateIO(BOOL fActivate,LPMSG lpMsg)270 HRESULT STDMETHODCALLTYPE CBaseBarSite::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
271 {
272 if (!fCurrentActiveBar)
273 return S_OK;
274
275 return IUnknown_UIActivateIO(fCurrentActiveBar->fTheBar, fActivate, lpMsg);
276 }
277
HasFocusIO()278 HRESULT STDMETHODCALLTYPE CBaseBarSite::HasFocusIO()
279 {
280 if (!fCurrentActiveBar)
281 return S_FALSE;
282
283 return IUnknown_HasFocusIO(fCurrentActiveBar->fTheBar);
284 }
285
TranslateAcceleratorIO(LPMSG lpMsg)286 HRESULT STDMETHODCALLTYPE CBaseBarSite::TranslateAcceleratorIO(LPMSG lpMsg)
287 {
288 if (!fCurrentActiveBar)
289 {
290 if (lpMsg)
291 {
292 TranslateMessage(lpMsg);
293 DispatchMessage(lpMsg);
294 }
295 return S_OK;
296 }
297
298 return IUnknown_TranslateAcceleratorIO(fCurrentActiveBar->fTheBar, lpMsg);
299 }
300
QueryService(REFGUID guidService,REFIID riid,void ** ppvObject)301 HRESULT STDMETHODCALLTYPE CBaseBarSite::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
302 {
303 CComPtr<IServiceProvider> serviceProvider;
304 HRESULT hResult;
305
306 if (fDeskBarSite == NULL)
307 return E_FAIL;
308 hResult = fDeskBarSite->QueryInterface(IID_PPV_ARG(IServiceProvider, &serviceProvider));
309 if (FAILED_UNEXPECTEDLY(hResult))
310 return hResult;
311 // called for SID_STopLevelBrowser, IID_IBrowserService to find top level browser
312 // called for SID_IWebBrowserApp, IID_IConnectionPointContainer
313 // connection point called for DIID_DWebBrowserEvents2 to establish connection
314 return serviceProvider->QueryService(guidService, riid, ppvObject);
315 }
316
OnWinEvent(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam,LRESULT * theResult)317 HRESULT STDMETHODCALLTYPE CBaseBarSite::OnWinEvent(
318 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
319 {
320 CComPtr<IDeskBar> deskBar;
321 CComPtr<IWinEventHandler> winEventHandler;
322 NMHDR *notifyHeader;
323 // RECT newBounds;
324 HRESULT hResult;
325 LRESULT result;
326
327 hResult = S_OK;
328 if (uMsg == WM_NOTIFY)
329 {
330 notifyHeader = (NMHDR *)lParam;
331 if (notifyHeader->hwndFrom == m_hWnd)
332 {
333 switch (notifyHeader->code)
334 {
335 case RBN_AUTOSIZE:
336 // For now, don't notify basebar we tried to resize ourselves, we don't
337 // get correct values at the moment.
338 #if 0
339 hResult = fDeskBarSite->QueryInterface(IID_PPV_ARG(IDeskBar, &deskBar));
340 GetClientRect(&newBounds);
341 hResult = deskBar->OnPosRectChangeDB(&newBounds);
342
343 #endif
344 break;
345 case NM_CUSTOMDRAW:
346 result = OnCustomDraw((LPNMCUSTOMDRAW)lParam);
347 if (theResult)
348 *theResult = result;
349 return S_OK;
350 }
351 }
352 }
353 if (fCurrentActiveBar != NULL)
354 {
355 hResult = fCurrentActiveBar->fTheBar->QueryInterface(
356 IID_PPV_ARG(IWinEventHandler, &winEventHandler));
357 if (SUCCEEDED(hResult) && winEventHandler.p != NULL)
358 hResult = winEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult);
359 }
360 return hResult;
361 }
362
IsWindowOwner(HWND hWnd)363 HRESULT STDMETHODCALLTYPE CBaseBarSite::IsWindowOwner(HWND hWnd)
364 {
365 return E_NOTIMPL;
366 }
367
OnFocusChangeIS(IUnknown * punkObj,BOOL fSetFocus)368 HRESULT STDMETHODCALLTYPE CBaseBarSite::OnFocusChangeIS (IUnknown *punkObj, BOOL fSetFocus)
369 {
370 // FIXME: should we directly pass-through, or advertise ourselves as focus owner ?
371 return IUnknown_OnFocusChangeIS(fDeskBarSite, punkObj, fSetFocus);
372 }
373
SetDeskBarSite(IUnknown * punkSite)374 HRESULT STDMETHODCALLTYPE CBaseBarSite::SetDeskBarSite(IUnknown *punkSite)
375 {
376 CComPtr<IOleWindow> oleWindow;
377 HWND ownerWindow;
378 HRESULT hResult;
379 DWORD dwBandID;
380
381 if (punkSite == NULL)
382 {
383 TRACE("Destroying site\n");
384 /* Cleanup our bands */
385 for (UINT i = EnumBands(-1, NULL); i;)
386 {
387 hResult = EnumBands(--i, &dwBandID);
388 if (!FAILED_UNEXPECTEDLY(hResult))
389 RemoveBand(dwBandID);
390 }
391 fDeskBarSite = NULL;
392 }
393 else
394 {
395 TBBUTTON closeBtn;
396 HBITMAP hBmp;
397
398 hResult = punkSite->QueryInterface(IID_PPV_ARG(IOleWindow, &oleWindow));
399 if (FAILED_UNEXPECTEDLY(hResult))
400 return hResult;
401 hResult = punkSite->QueryInterface(IID_PPV_ARG(IUnknown, &fDeskBarSite));
402 if (FAILED_UNEXPECTEDLY(hResult))
403 return hResult;
404 hResult = oleWindow->GetWindow(&ownerWindow);
405 if (FAILED_UNEXPECTEDLY(hResult))
406 return hResult;
407
408 DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER |
409 RBS_VARHEIGHT | RBS_REGISTERDROP | RBS_AUTOSIZE | RBS_VERTICALGRIPPER | RBS_DBLCLKTOGGLE |
410 CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE;
411 if (fVertical)
412 dwStyle |= CCS_VERT;
413
414 /* Create site window */
415 HWND tmp = CreateWindowW(REBARCLASSNAMEW, NULL, dwStyle, 0, 0, 0, 0, ownerWindow, NULL,
416 _AtlBaseModule.GetModuleInstance(), NULL);
417
418 /* Give window management to ATL */
419 SubclassWindow(tmp);
420
421 SendMessage(RB_SETTEXTCOLOR, 0, CLR_DEFAULT);
422 SendMessage(RB_SETBKCOLOR, 0, CLR_DEFAULT);
423
424 /* Create close toolbar and imagelist */
425 toolbarWnd = CreateWindowW(TOOLBARCLASSNAMEW, NULL,
426 WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
427 TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS |
428 CCS_NOMOVEY | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER
429 , 0, 0, 0, 0, m_hWnd, NULL, _AtlBaseModule.GetModuleInstance(), NULL);
430
431 toolImageList = ImageList_Create(13, 11, ILC_COLOR24 | ILC_MASK, 3, 0);
432
433 hBmp = (HBITMAP)LoadImage(_AtlBaseModule.GetModuleInstance(),
434 MAKEINTRESOURCE(IDB_BANDBUTTONS), IMAGE_BITMAP, 0, 0,
435 LR_LOADTRANSPARENT);
436
437 ImageList_AddMasked(toolImageList, hBmp, RGB(192, 192, 192));
438 DeleteObject(hBmp);
439
440 SendMessage(toolbarWnd, TB_SETIMAGELIST, 0, (LPARAM)toolImageList);
441
442 /* Add button to toolbar */
443 closeBtn.iBitmap = MAKELONG(1, 0);
444 closeBtn.idCommand = IDM_BASEBAR_CLOSE;
445 closeBtn.fsState = TBSTATE_ENABLED;
446 closeBtn.fsStyle = BTNS_BUTTON;
447 ZeroMemory(closeBtn.bReserved, sizeof(closeBtn.bReserved));
448 closeBtn.dwData = 0;
449 closeBtn.iString = (INT_PTR)L"Close";
450
451 SendMessage(toolbarWnd, TB_INSERTBUTTON, 0, (LPARAM)&closeBtn);
452 SendMessage(toolbarWnd, TB_SETMAXTEXTROWS, 0, 0);
453 //SendMessage(toolbarWnd, TB_AUTOSIZE, 0, 0);
454 }
455 return S_OK;
456 }
457
SetModeDBC(DWORD dwMode)458 HRESULT STDMETHODCALLTYPE CBaseBarSite::SetModeDBC(DWORD dwMode)
459 {
460 return E_NOTIMPL;
461 }
462
UIActivateDBC(DWORD dwState)463 HRESULT STDMETHODCALLTYPE CBaseBarSite::UIActivateDBC(DWORD dwState)
464 {
465 return E_NOTIMPL;
466 }
467
GetSize(DWORD dwWhich,LPRECT prc)468 HRESULT STDMETHODCALLTYPE CBaseBarSite::GetSize(DWORD dwWhich, LPRECT prc)
469 {
470 return E_NOTIMPL;
471 }
472
QueryStatus(const GUID * pguidCmdGroup,ULONG cCmds,OLECMD prgCmds[],OLECMDTEXT * pCmdText)473 HRESULT STDMETHODCALLTYPE CBaseBarSite::QueryStatus(const GUID *pguidCmdGroup,
474 ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText)
475 {
476 return E_NOTIMPL;
477 }
478
Exec(const GUID * pguidCmdGroup,DWORD nCmdID,DWORD nCmdexecopt,VARIANT * pvaIn,VARIANT * pvaOut)479 HRESULT STDMETHODCALLTYPE CBaseBarSite::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
480 DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
481 {
482 if (IsEqualIID(*pguidCmdGroup, IID_IDeskBand))
483 {
484 switch (nCmdID)
485 {
486 case 0:
487 //update band info ?
488 case 1: // insert a new band
489 if (V_VT(pvaIn) != VT_UNKNOWN)
490 return E_INVALIDARG;
491 return InsertBar(V_UNKNOWN(pvaIn));
492 case 0x17:
493 // redim band
494 break;
495 }
496 }
497 return E_FAIL;
498 }
499
GetInternalBandInfo(UINT uBand,REBARBANDINFO * pBandInfo)500 HRESULT CBaseBarSite::GetInternalBandInfo(UINT uBand, REBARBANDINFO *pBandInfo)
501 {
502 if (!pBandInfo)
503 return E_INVALIDARG;
504 memset(pBandInfo, 0, sizeof(REBARBANDINFO));
505 pBandInfo->cbSize = sizeof(REBARBANDINFO);
506 pBandInfo->fMask = RBBIM_LPARAM | RBBIM_ID;
507
508 // Grab our bandinfo from rebar control
509 if (!SendMessage(RB_GETBANDINFO, uBand, reinterpret_cast<LPARAM>(pBandInfo)))
510 return E_INVALIDARG;
511 return S_OK;
512 }
513
GetInternalBandInfo(UINT uBand,REBARBANDINFO * pBandInfo,DWORD fMask)514 HRESULT CBaseBarSite::GetInternalBandInfo(UINT uBand, REBARBANDINFO *pBandInfo, DWORD fMask)
515 {
516 if (!pBandInfo)
517 return E_INVALIDARG;
518 pBandInfo->cbSize = sizeof(REBARBANDINFO);
519 pBandInfo->fMask = fMask;
520
521 // Grab our bandinfo from rebar control
522 if (!SendMessage(RB_GETBANDINFO, uBand, reinterpret_cast<LPARAM>(pBandInfo)))
523 return E_INVALIDARG;
524 return S_OK;
525 }
526
AddBand(IUnknown * punk)527 HRESULT STDMETHODCALLTYPE CBaseBarSite::AddBand(IUnknown *punk)
528 {
529 return InsertBar(punk);
530 }
531
EnumBands(UINT uBand,DWORD * pdwBandID)532 HRESULT STDMETHODCALLTYPE CBaseBarSite::EnumBands(UINT uBand, DWORD *pdwBandID)
533 {
534 REBARBANDINFO bandInfo;
535
536 if (uBand == -1ul)
537 return (HRESULT)SendMessage(RB_GETBANDCOUNT, 0, 0);
538 if (pdwBandID == NULL)
539 return E_INVALIDARG;
540
541 if (!SUCCEEDED(GetInternalBandInfo(uBand, &bandInfo)))
542 return E_INVALIDARG;
543 *pdwBandID = bandInfo.wID;
544 return S_OK;
545 }
546
QueryBand(DWORD dwBandID,IDeskBand ** ppstb,DWORD * pdwState,LPWSTR pszName,int cchName)547 HRESULT STDMETHODCALLTYPE CBaseBarSite::QueryBand(DWORD dwBandID, IDeskBand **ppstb,
548 DWORD *pdwState, LPWSTR pszName, int cchName)
549 {
550 return E_NOTIMPL;
551 }
552
SetBandState(DWORD dwBandID,DWORD dwMask,DWORD dwState)553 HRESULT STDMETHODCALLTYPE CBaseBarSite::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
554 {
555 return E_NOTIMPL;
556 }
557
RemoveBand(DWORD dwBandID)558 HRESULT STDMETHODCALLTYPE CBaseBarSite::RemoveBand(DWORD dwBandID)
559 {
560 REBARBANDINFO bandInfo;
561 HRESULT hr;
562 CBarInfo *pInfo;
563 CComPtr<IObjectWithSite> pSite;
564 CComPtr<IDockingWindow> pDockWnd;
565 DWORD index;
566
567 // Retrieve the right index of the coolbar knowing the id
568 index = SendMessage(RB_IDTOINDEX, dwBandID, 0);
569 if (index == 0xffffffff)
570 return E_INVALIDARG;
571
572 if (FAILED_UNEXPECTEDLY(GetInternalBandInfo(index, &bandInfo)))
573 return E_INVALIDARG;
574
575 pInfo = reinterpret_cast<CBarInfo*>(bandInfo.lParam);
576 if (!pInfo)
577 return E_INVALIDARG;
578
579 /* Windows sends a CloseDW before setting site to NULL */
580 hr = pInfo->fTheBar->QueryInterface(IID_PPV_ARG(IDockingWindow, &pDockWnd));
581 if (SUCCEEDED(hr))
582 pDockWnd->CloseDW(0);
583
584 hr = pInfo->fTheBar->QueryInterface(IID_PPV_ARG(IObjectWithSite, &pSite));
585 if (SUCCEEDED(hr))
586 pSite->SetSite(NULL);
587
588 // Delete the band from rebar
589 if (!SendMessage(RB_DELETEBAND, index, 0))
590 {
591 ERR("Can't delete the band\n");
592 return E_INVALIDARG;
593 }
594 if (pInfo == fCurrentActiveBar)
595 {
596 // FIXME: what to do when we are deleting active bar ? Let's assume we remove it for now
597 fCurrentActiveBar = NULL;
598 }
599 delete pInfo;
600 return S_OK;
601 }
602
GetBandObject(DWORD dwBandID,REFIID riid,void ** ppv)603 HRESULT STDMETHODCALLTYPE CBaseBarSite::GetBandObject(DWORD dwBandID, REFIID riid, void **ppv)
604 {
605 REBARBANDINFO bandInfo;
606 HRESULT hr;
607 CBarInfo *pInfo;
608 DWORD index;
609
610 if (ppv == NULL)
611 return E_POINTER;
612
613 // Retrieve the right index of the coolbar knowing the id
614 index = SendMessage(RB_IDTOINDEX, dwBandID, 0);
615 if (index == 0xffffffff)
616 return E_INVALIDARG;
617
618 if (FAILED_UNEXPECTEDLY(GetInternalBandInfo(index, &bandInfo)))
619 return E_INVALIDARG;
620
621 pInfo = reinterpret_cast<CBarInfo*>(bandInfo.lParam);
622 hr = pInfo->fTheBar->QueryInterface(riid, ppv);
623 if (!SUCCEEDED(hr))
624 return E_NOINTERFACE;
625 return S_OK;
626 }
627
SetBandSiteInfo(const BANDSITEINFO * pbsinfo)628 HRESULT STDMETHODCALLTYPE CBaseBarSite::SetBandSiteInfo(const BANDSITEINFO *pbsinfo)
629 {
630 if (pbsinfo == NULL)
631 return E_POINTER;
632 return E_NOTIMPL;
633 }
634
GetBandSiteInfo(BANDSITEINFO * pbsinfo)635 HRESULT STDMETHODCALLTYPE CBaseBarSite::GetBandSiteInfo(BANDSITEINFO *pbsinfo)
636 {
637 if (pbsinfo == NULL)
638 return E_POINTER;
639 return E_NOTIMPL;
640 }
641
GetClassID(CLSID * pClassID)642 HRESULT STDMETHODCALLTYPE CBaseBarSite::GetClassID(CLSID *pClassID)
643 {
644 if (pClassID == NULL)
645 return E_POINTER;
646 // TODO: what class to return here?
647 return E_NOTIMPL;
648 }
649
IsDirty()650 HRESULT STDMETHODCALLTYPE CBaseBarSite::IsDirty()
651 {
652 return E_NOTIMPL;
653 }
654
Load(IStream * pStm)655 HRESULT STDMETHODCALLTYPE CBaseBarSite::Load(IStream *pStm)
656 {
657 return E_NOTIMPL;
658 }
659
Save(IStream * pStm,BOOL fClearDirty)660 HRESULT STDMETHODCALLTYPE CBaseBarSite::Save(IStream *pStm, BOOL fClearDirty)
661 {
662 return E_NOTIMPL;
663 }
664
GetSizeMax(ULARGE_INTEGER * pcbSize)665 HRESULT STDMETHODCALLTYPE CBaseBarSite::GetSizeMax(ULARGE_INTEGER *pcbSize)
666 {
667 if (pcbSize == NULL)
668 return E_POINTER;
669 return E_NOTIMPL;
670 }
671
OnNotify(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)672 LRESULT CBaseBarSite::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
673 {
674 NMHDR *notifyHeader;
675
676 notifyHeader = reinterpret_cast<NMHDR *>(lParam);
677 if (notifyHeader->hwndFrom == m_hWnd)
678 {
679 }
680 bHandled = FALSE; /* forward notification to parent */
681 return 0;
682 }
683
OnCommand(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)684 LRESULT CBaseBarSite::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
685 {
686 if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDM_BASEBAR_CLOSE)
687 {
688 /* Tell the base bar to hide */
689 IUnknown_Exec(fDeskBarSite, IID_IDeskBarClient, 0, 0, NULL, NULL);
690 bHandled = TRUE;
691 }
692 return 0;
693 }
694
OnCustomDraw(LPNMCUSTOMDRAW pnmcd)695 LRESULT CBaseBarSite::OnCustomDraw(LPNMCUSTOMDRAW pnmcd)
696 {
697 switch (pnmcd->dwDrawStage)
698 {
699 case CDDS_PREPAINT:
700 case CDDS_PREERASE:
701 return CDRF_NOTIFYITEMDRAW;
702 case CDDS_ITEMPREPAINT:
703 if (fVertical)
704 {
705 REBARBANDINFO info;
706 WCHAR wszTitle[MAX_PATH];
707 DWORD index;
708 UINT pad = GetSystemMetrics(SM_CXEDGE), leftpad = max(pad * 2, 4);
709 UINT btnw = 20, btnh = 18, btnarea = 1 + btnw + 1;
710 HFONT newFont, oldFont;
711
712 index = SendMessage(RB_IDTOINDEX, fCurrentActiveBar->fBandID , 0);
713 ZeroMemory(&info, sizeof(info));
714 ZeroMemory(wszTitle, sizeof(wszTitle));
715 DrawEdge(pnmcd->hdc, &pnmcd->rc, EDGE_ETCHED, BF_BOTTOM);
716 // We also resize our close button
717 ::SetWindowPos(toolbarWnd, HWND_TOP, pnmcd->rc.right - btnarea, 0, btnw, btnh, SWP_SHOWWINDOW);
718 // Draw the text
719 info.cch = MAX_PATH;
720 info.lpText = wszTitle;
721 RECT rt = pnmcd->rc;
722 rt.right -= btnarea;
723 rt.left += leftpad;
724 rt.bottom -= 1;
725 if (FAILED_UNEXPECTEDLY(GetInternalBandInfo(index, &info, RBBIM_TEXT)))
726 return CDRF_SKIPDEFAULT;
727 newFont = GetTitleFont();
728 if (newFont)
729 oldFont = (HFONT)SelectObject(pnmcd->hdc, newFont);
730 COLORREF orgclrtxt = SetTextColor(pnmcd->hdc, GetSysColor(COLOR_BTNTEXT));
731 DrawText(pnmcd->hdc, info.lpText, -1, &rt, DT_SINGLELINE | DT_LEFT | DT_VCENTER);
732 SetTextColor(pnmcd->hdc, orgclrtxt);
733 SelectObject(pnmcd->hdc, oldFont);
734 DeleteObject(newFont);
735 return CDRF_SKIPDEFAULT;
736 }
737 else
738 {
739 DrawEdge(pnmcd->hdc, &pnmcd->rc, EDGE_ETCHED, BF_BOTTOM);
740 // We also resize our close button
741 ::SetWindowPos(toolbarWnd, HWND_TOP, 0, 2, 20, 18, SWP_SHOWWINDOW);
742 }
743 return CDRF_SKIPDEFAULT;
744 default:
745 break;
746 }
747 return CDRF_DODEFAULT;
748 }
749
GetTitleFont()750 HFONT CBaseBarSite::GetTitleFont()
751 {
752 NONCLIENTMETRICS mt;
753 mt.cbSize = sizeof(mt);
754 if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(mt), &mt, 0))
755 {
756 ERR("Can't get system parameters !\n");
757 return NULL;
758 }
759 return CreateFontIndirect(&mt.lfMenuFont);
760
761 }
762
FindBandByGUID(REFGUID pGuid,DWORD * pdwBandID)763 HRESULT CBaseBarSite::FindBandByGUID(REFGUID pGuid, DWORD *pdwBandID)
764 {
765 DWORD numBands;
766 DWORD i;
767 REBARBANDINFO bandInfo;
768 CBarInfo *realInfo;
769
770 numBands = EnumBands(-1, NULL);
771 for (i = 0; i < numBands; i++)
772 {
773 if (FAILED_UNEXPECTEDLY(GetInternalBandInfo(i, &bandInfo)))
774 return E_FAIL;
775 realInfo = (CBarInfo*)bandInfo.lParam;
776 if (IsEqualGUID(pGuid, realInfo->fBarClass))
777 {
778 *pdwBandID = realInfo->fBandID;
779 return S_OK;
780 }
781 }
782 return S_FALSE;
783 }
784
ShowBand(DWORD dwBandID)785 HRESULT CBaseBarSite::ShowBand(DWORD dwBandID)
786 {
787 UINT index;
788 CComPtr<IDeskBand> dockingWindow;
789 HRESULT hResult;
790 REBARBANDINFO bandInfo;
791
792 // show our band
793 hResult = GetBandObject(dwBandID, IID_PPV_ARG(IDeskBand, &dockingWindow));
794 if (FAILED_UNEXPECTEDLY(hResult))
795 return E_FAIL;
796
797 hResult = dockingWindow->ShowDW(TRUE);
798
799 // Hide old band while adding new one
800 if (fCurrentActiveBar && fCurrentActiveBar->fBandID != dwBandID)
801 {
802 DWORD index;
803 index = SendMessage(RB_IDTOINDEX, fCurrentActiveBar->fBandID, 0);
804 if (index != 0xffffffff)
805 SendMessage(RB_SHOWBAND, index, 0);
806 }
807 if (FAILED_UNEXPECTEDLY(hResult))
808 return hResult;
809
810 // Display the current band
811 index = SendMessage(RB_IDTOINDEX, dwBandID, 0);
812 if (index != 0xffffffff)
813 SendMessage(RB_SHOWBAND, index, 1);
814 if (FAILED_UNEXPECTEDLY(GetInternalBandInfo(index, &bandInfo)))
815 return E_FAIL;
816 fCurrentActiveBar = (CBarInfo*)bandInfo.lParam;
817 return S_OK;
818 }
819
CBaseBarSite_CreateInstance(REFIID riid,void ** ppv,BOOL bVertical)820 HRESULT CBaseBarSite_CreateInstance(REFIID riid, void **ppv, BOOL bVertical)
821 {
822 return ShellObjectCreatorInit<CBaseBarSite, BOOL>(bVertical, riid, ppv);
823 }
824