xref: /reactos/dll/win32/browseui/basebarsite.cpp (revision d7fd62d4)
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();
73     HRESULT Initialize(BOOL vert) { fVertical = vert; return S_OK; };
74 private:
75     HRESULT InsertBar(IUnknown *newBar);
76 
77     // *** IOleWindow methods ***
78     virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
79     virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
80 
81     // *** IInputObject methods ***
82     virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL fActivate, LPMSG lpMsg);
83     virtual HRESULT STDMETHODCALLTYPE HasFocusIO();
84     virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg);
85 
86     // *** IServiceProvider methods ***
87     virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
88 
89     // *** IWinEventHandler methods ***
90     virtual HRESULT STDMETHODCALLTYPE OnWinEvent(
91         HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult);
92     virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd);
93 
94     // *** IInputObjectSite specific methods ***
95     virtual HRESULT STDMETHODCALLTYPE OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus);
96 
97     // *** IDeskBarClient methods ***
98     virtual HRESULT STDMETHODCALLTYPE SetDeskBarSite(IUnknown *punkSite);
99     virtual HRESULT STDMETHODCALLTYPE SetModeDBC(DWORD dwMode);
100     virtual HRESULT STDMETHODCALLTYPE UIActivateDBC(DWORD dwState);
101     virtual HRESULT STDMETHODCALLTYPE GetSize(DWORD dwWhich, LPRECT prc);
102 
103     // *** IOleCommandTarget methods ***
104     virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
105         OLECMD prgCmds[  ], OLECMDTEXT *pCmdText);
106     virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
107         DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
108 
109     // *** IBandSite specific methods ***
110     virtual HRESULT STDMETHODCALLTYPE AddBand(IUnknown *punk);
111     virtual HRESULT STDMETHODCALLTYPE EnumBands(UINT uBand, DWORD *pdwBandID);
112     virtual HRESULT STDMETHODCALLTYPE QueryBand(DWORD dwBandID, IDeskBand **ppstb, DWORD *pdwState,
113         LPWSTR pszName, int cchName);
114     virtual HRESULT STDMETHODCALLTYPE SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState);
115     virtual HRESULT STDMETHODCALLTYPE RemoveBand(DWORD dwBandID);
116     virtual HRESULT STDMETHODCALLTYPE GetBandObject(DWORD dwBandID, REFIID riid, void **ppv);
117     virtual HRESULT STDMETHODCALLTYPE SetBandSiteInfo(const BANDSITEINFO *pbsinfo);
118     virtual HRESULT STDMETHODCALLTYPE GetBandSiteInfo(BANDSITEINFO *pbsinfo);
119 
120     // *** IPersist methods ***
121     virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
122 
123     // *** IPersistStream methods ***
124     virtual HRESULT STDMETHODCALLTYPE IsDirty();
125     virtual HRESULT STDMETHODCALLTYPE Load(IStream *pStm);
126     virtual HRESULT STDMETHODCALLTYPE Save(IStream *pStm, BOOL fClearDirty);
127     virtual HRESULT STDMETHODCALLTYPE GetSizeMax(ULARGE_INTEGER *pcbSize);
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 
164 CBaseBarSite::CBaseBarSite() : fVertical(TRUE)
165 {
166     fCurrentActiveBar = NULL;
167     fNextBandID = 1;
168 }
169 
170 CBaseBarSite::~CBaseBarSite()
171 {
172     TRACE("CBaseBarSite deleted\n");
173 }
174 
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 
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 
265 HRESULT STDMETHODCALLTYPE CBaseBarSite::ContextSensitiveHelp(BOOL fEnterMode)
266 {
267     return E_NOTIMPL;
268 }
269 
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 
278 HRESULT STDMETHODCALLTYPE CBaseBarSite::HasFocusIO()
279 {
280     if (!fCurrentActiveBar)
281         return S_FALSE;
282 
283     return IUnknown_HasFocusIO(fCurrentActiveBar->fTheBar);
284 }
285 
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 
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 
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 
363 HRESULT STDMETHODCALLTYPE CBaseBarSite::IsWindowOwner(HWND hWnd)
364 {
365     return E_NOTIMPL;
366 }
367 
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 
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 
384         TRACE("Destroying site \n");
385         /* Cleanup our bands */
386         while(SUCCEEDED(EnumBands(-1, &dwBandID)) && dwBandID)
387         {
388             hResult = EnumBands(0, &dwBandID);
389             if(FAILED_UNEXPECTEDLY(hResult))
390                 continue;
391             RemoveBand(dwBandID);
392         }
393         fDeskBarSite = NULL;
394     }
395     else
396     {
397         TBBUTTON closeBtn;
398         HBITMAP hBmp;
399 
400         hResult = punkSite->QueryInterface(IID_PPV_ARG(IOleWindow, &oleWindow));
401         if (FAILED_UNEXPECTEDLY(hResult))
402             return hResult;
403         hResult = punkSite->QueryInterface(IID_PPV_ARG(IUnknown, &fDeskBarSite));
404         if (FAILED_UNEXPECTEDLY(hResult))
405             return hResult;
406         hResult = oleWindow->GetWindow(&ownerWindow);
407         if (FAILED_UNEXPECTEDLY(hResult))
408             return hResult;
409 
410         DWORD dwStyle =  WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER |
411              RBS_VARHEIGHT | RBS_REGISTERDROP | RBS_AUTOSIZE | RBS_VERTICALGRIPPER | RBS_DBLCLKTOGGLE |
412              CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE;
413         if (fVertical)
414             dwStyle |= CCS_VERT;
415 
416         /* Create site window */
417         HWND tmp = CreateWindowW(REBARCLASSNAMEW, NULL, dwStyle, 0, 0, 0, 0, ownerWindow, NULL,
418                     _AtlBaseModule.GetModuleInstance(), NULL);
419 
420         /* Give window management to ATL */
421         SubclassWindow(tmp);
422 
423         SendMessage(RB_SETTEXTCOLOR, 0, CLR_DEFAULT);
424         SendMessage(RB_SETBKCOLOR, 0, CLR_DEFAULT);
425 
426         /* Create close toolbar and imagelist */
427         toolbarWnd = CreateWindowW(TOOLBARCLASSNAMEW, NULL,
428             WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
429             TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS |
430             CCS_NOMOVEY | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER
431             , 0, 0, 0, 0, m_hWnd, NULL, _AtlBaseModule.GetModuleInstance(), NULL);
432 
433         toolImageList = ImageList_Create(13, 11, ILC_COLOR24 | ILC_MASK, 3, 0);
434 
435         hBmp = (HBITMAP)LoadImage(_AtlBaseModule.GetModuleInstance(),
436             MAKEINTRESOURCE(IDB_BANDBUTTONS), IMAGE_BITMAP, 0, 0,
437             LR_LOADTRANSPARENT);
438 
439         ImageList_AddMasked(toolImageList, hBmp, RGB(192, 192, 192));
440         DeleteObject(hBmp);
441 
442         SendMessage(toolbarWnd, TB_SETIMAGELIST, 0, (LPARAM)toolImageList);
443 
444         /* Add button to toolbar */
445         closeBtn.iBitmap = MAKELONG(1, 0);
446         closeBtn.idCommand = IDM_BASEBAR_CLOSE;
447         closeBtn.fsState = TBSTATE_ENABLED;
448         closeBtn.fsStyle = BTNS_BUTTON;
449         ZeroMemory(closeBtn.bReserved, sizeof(closeBtn.bReserved));
450         closeBtn.dwData = 0;
451         closeBtn.iString = (INT_PTR)L"Close";
452 
453         SendMessage(toolbarWnd, TB_INSERTBUTTON, 0, (LPARAM)&closeBtn);
454         SendMessage(toolbarWnd, TB_SETMAXTEXTROWS, 0, 0);
455         //SendMessage(toolbarWnd, TB_AUTOSIZE, 0, 0);
456     }
457     return S_OK;
458 }
459 
460 HRESULT STDMETHODCALLTYPE CBaseBarSite::SetModeDBC(DWORD dwMode)
461 {
462     return E_NOTIMPL;
463 }
464 
465 HRESULT STDMETHODCALLTYPE CBaseBarSite::UIActivateDBC(DWORD dwState)
466 {
467     return E_NOTIMPL;
468 }
469 
470 HRESULT STDMETHODCALLTYPE CBaseBarSite::GetSize(DWORD dwWhich, LPRECT prc)
471 {
472     return E_NOTIMPL;
473 }
474 
475 HRESULT STDMETHODCALLTYPE CBaseBarSite::QueryStatus(const GUID *pguidCmdGroup,
476     ULONG cCmds, OLECMD prgCmds[  ], OLECMDTEXT *pCmdText)
477 {
478     return E_NOTIMPL;
479 }
480 
481 HRESULT STDMETHODCALLTYPE CBaseBarSite::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
482     DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
483 {
484     if (IsEqualIID(*pguidCmdGroup, IID_IDeskBand))
485     {
486         switch (nCmdID)
487         {
488             case 0:
489                 //update band info ?
490             case 1:     // insert a new band
491                 if (V_VT(pvaIn) != VT_UNKNOWN)
492                     return E_INVALIDARG;
493                 return InsertBar(V_UNKNOWN(pvaIn));
494             case 0x17:
495                 // redim band
496                 break;
497         }
498     }
499     return E_FAIL;
500 }
501 
502 HRESULT CBaseBarSite::GetInternalBandInfo(UINT uBand, REBARBANDINFO *pBandInfo)
503 {
504     if (!pBandInfo)
505         return E_INVALIDARG;
506     memset(pBandInfo, 0, sizeof(REBARBANDINFO));
507     pBandInfo->cbSize = sizeof(REBARBANDINFO);
508     pBandInfo->fMask = RBBIM_LPARAM | RBBIM_ID;
509 
510     // Grab our bandinfo from rebar control
511     if (!SendMessage(RB_GETBANDINFO, uBand, reinterpret_cast<LPARAM>(pBandInfo)))
512         return E_INVALIDARG;
513     return S_OK;
514 }
515 
516 HRESULT CBaseBarSite::GetInternalBandInfo(UINT uBand, REBARBANDINFO *pBandInfo, DWORD fMask)
517 {
518     if (!pBandInfo)
519         return E_INVALIDARG;
520     pBandInfo->cbSize = sizeof(REBARBANDINFO);
521     pBandInfo->fMask = fMask;
522 
523     // Grab our bandinfo from rebar control
524     if (!SendMessage(RB_GETBANDINFO, uBand, reinterpret_cast<LPARAM>(pBandInfo)))
525         return E_INVALIDARG;
526     return S_OK;
527 }
528 
529 HRESULT STDMETHODCALLTYPE CBaseBarSite::AddBand(IUnknown *punk)
530 {
531     return InsertBar(punk);
532 }
533 
534 HRESULT STDMETHODCALLTYPE CBaseBarSite::EnumBands(UINT uBand, DWORD *pdwBandID)
535 {
536     REBARBANDINFO bandInfo;
537 
538     if (pdwBandID == NULL)
539         return E_INVALIDARG;
540     if (uBand == 0xffffffff)
541     {
542         *pdwBandID = (DWORD)SendMessage(RB_GETBANDCOUNT, 0, 0);
543         return S_OK;
544     }
545     if (!SUCCEEDED(GetInternalBandInfo(uBand, &bandInfo)))
546         return E_INVALIDARG;
547     *pdwBandID = bandInfo.wID;
548     return S_OK;
549 }
550 
551 HRESULT STDMETHODCALLTYPE CBaseBarSite::QueryBand(DWORD dwBandID, IDeskBand **ppstb,
552     DWORD *pdwState, LPWSTR pszName, int cchName)
553 {
554     return E_NOTIMPL;
555 }
556 
557 HRESULT STDMETHODCALLTYPE CBaseBarSite::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
558 {
559     return E_NOTIMPL;
560 }
561 
562 HRESULT STDMETHODCALLTYPE CBaseBarSite::RemoveBand(DWORD dwBandID)
563 {
564     REBARBANDINFO                   bandInfo;
565     HRESULT                         hr;
566     CBarInfo                        *pInfo;
567     CComPtr<IObjectWithSite>        pSite;
568     CComPtr<IDeskBand>              pDockWnd;
569     DWORD                           index;
570 
571     // Retrieve the right index of the coolbar knowing the id
572     index = SendMessage(RB_IDTOINDEX, dwBandID, 0);
573     if (index == 0xffffffff)
574        return E_INVALIDARG;
575 
576     if (FAILED_UNEXPECTEDLY(GetInternalBandInfo(index, &bandInfo)))
577         return E_INVALIDARG;
578 
579     pInfo = reinterpret_cast<CBarInfo*>(bandInfo.lParam);
580     if (!pInfo)
581         return E_INVALIDARG;
582 
583     hr = pInfo->fTheBar->QueryInterface(IID_PPV_ARG(IDeskBand, &pDockWnd));
584     if (FAILED_UNEXPECTEDLY(hr))
585     {
586         return E_NOINTERFACE;
587     }
588     hr = pInfo->fTheBar->QueryInterface(IID_PPV_ARG(IObjectWithSite, &pSite));
589     if (FAILED_UNEXPECTEDLY(hr))
590     {
591         return E_NOINTERFACE;
592     }
593     /* Windows sends a CloseDW before setting site to NULL */
594     pDockWnd->CloseDW(0);
595     pSite->SetSite(NULL);
596 
597     // Delete the band from rebar
598     if (!SendMessage(RB_DELETEBAND, index, 0))
599     {
600         ERR("Can't delete the band\n");
601         return E_INVALIDARG;
602     }
603     if (pInfo == fCurrentActiveBar)
604     {
605         // FIXME: what to do when we are deleting active bar ? Let's assume we remove it for now
606         fCurrentActiveBar = NULL;
607     }
608     delete pInfo;
609     return S_OK;
610 }
611 
612 HRESULT STDMETHODCALLTYPE CBaseBarSite::GetBandObject(DWORD dwBandID, REFIID riid, void **ppv)
613 {
614     REBARBANDINFO               bandInfo;
615     HRESULT                     hr;
616     CBarInfo                    *pInfo;
617     DWORD                       index;
618 
619     if (ppv == NULL)
620         return E_POINTER;
621 
622     // Retrieve the right index of the coolbar knowing the id
623     index = SendMessage(RB_IDTOINDEX, dwBandID, 0);
624     if (index == 0xffffffff)
625        return E_INVALIDARG;
626 
627     if (FAILED_UNEXPECTEDLY(GetInternalBandInfo(index, &bandInfo)))
628         return E_INVALIDARG;
629 
630     pInfo = reinterpret_cast<CBarInfo*>(bandInfo.lParam);
631     hr = pInfo->fTheBar->QueryInterface(riid, ppv);
632     if (!SUCCEEDED(hr))
633         return E_NOINTERFACE;
634     return S_OK;
635 }
636 
637 HRESULT STDMETHODCALLTYPE CBaseBarSite::SetBandSiteInfo(const BANDSITEINFO *pbsinfo)
638 {
639     if (pbsinfo == NULL)
640         return E_POINTER;
641     return E_NOTIMPL;
642 }
643 
644 HRESULT STDMETHODCALLTYPE CBaseBarSite::GetBandSiteInfo(BANDSITEINFO *pbsinfo)
645 {
646     if (pbsinfo == NULL)
647         return E_POINTER;
648     return E_NOTIMPL;
649 }
650 
651 HRESULT STDMETHODCALLTYPE CBaseBarSite::GetClassID(CLSID *pClassID)
652 {
653     if (pClassID == NULL)
654         return E_POINTER;
655     // TODO: what class to return here?
656     return E_NOTIMPL;
657 }
658 
659 HRESULT STDMETHODCALLTYPE CBaseBarSite::IsDirty()
660 {
661     return E_NOTIMPL;
662 }
663 
664 HRESULT STDMETHODCALLTYPE CBaseBarSite::Load(IStream *pStm)
665 {
666     return E_NOTIMPL;
667 }
668 
669 HRESULT STDMETHODCALLTYPE CBaseBarSite::Save(IStream *pStm, BOOL fClearDirty)
670 {
671     return E_NOTIMPL;
672 }
673 
674 HRESULT STDMETHODCALLTYPE CBaseBarSite::GetSizeMax(ULARGE_INTEGER *pcbSize)
675 {
676     if (pcbSize == NULL)
677         return E_POINTER;
678     return E_NOTIMPL;
679 }
680 
681 LRESULT CBaseBarSite::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
682 {
683     NMHDR                       *notifyHeader;
684 
685     notifyHeader = reinterpret_cast<NMHDR *>(lParam);
686     if (notifyHeader->hwndFrom == m_hWnd)
687     {
688     }
689     bHandled = FALSE; /* forward notification to parent */
690     return 0;
691 }
692 
693 LRESULT CBaseBarSite::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
694 {
695     if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDM_BASEBAR_CLOSE)
696     {
697         /* Tell the base bar to hide */
698         IUnknown_Exec(fDeskBarSite, IID_IDeskBarClient, 0, 0, NULL, NULL);
699         bHandled = TRUE;
700     }
701     return 0;
702 }
703 
704 LRESULT CBaseBarSite::OnCustomDraw(LPNMCUSTOMDRAW pnmcd)
705 {
706     switch (pnmcd->dwDrawStage)
707     {
708         case CDDS_PREPAINT:
709         case CDDS_PREERASE:
710             return CDRF_NOTIFYITEMDRAW;
711         case CDDS_ITEMPREPAINT:
712             if (fVertical)
713             {
714                 REBARBANDINFO info;
715                 WCHAR wszTitle[MAX_PATH];
716                 DWORD index;
717                 RECT rt;
718                 HFONT newFont, oldFont;
719 
720                 index = SendMessage(RB_IDTOINDEX, fCurrentActiveBar->fBandID , 0);
721                 ZeroMemory(&info, sizeof(info));
722                 ZeroMemory(wszTitle, sizeof(wszTitle));
723                 DrawEdge(pnmcd->hdc, &pnmcd->rc, EDGE_ETCHED, BF_BOTTOM);
724                 // We also resize our close button
725                 ::SetWindowPos(toolbarWnd, HWND_TOP, pnmcd->rc.right - 22, 0, 20, 18, SWP_SHOWWINDOW);
726                 // Draw the text
727                 info.cch = MAX_PATH;
728                 info.lpText = wszTitle;
729                 rt = pnmcd->rc;
730                 rt.right -= 24;
731                 rt.left += 2;
732                 rt.bottom -= 1;
733                 if (FAILED_UNEXPECTEDLY(GetInternalBandInfo(index, &info, RBBIM_TEXT)))
734                     return CDRF_SKIPDEFAULT;
735                 newFont = GetTitleFont();
736                 if (newFont)
737                     oldFont = (HFONT)SelectObject(pnmcd->hdc, newFont);
738                 DrawText(pnmcd->hdc, info.lpText, -1, &rt, DT_SINGLELINE | DT_LEFT | DT_VCENTER);
739                 SelectObject(pnmcd->hdc, oldFont);
740                 DeleteObject(newFont);
741                 return CDRF_SKIPDEFAULT;
742             }
743             else
744             {
745                 DrawEdge(pnmcd->hdc, &pnmcd->rc, EDGE_ETCHED, BF_BOTTOM);
746                 // We also resize our close button
747                 ::SetWindowPos(toolbarWnd, HWND_TOP, 0, 2, 20, 18, SWP_SHOWWINDOW);
748             }
749             return CDRF_SKIPDEFAULT;
750         default:
751             break;
752     }
753     return CDRF_DODEFAULT;
754 }
755 
756 HFONT CBaseBarSite::GetTitleFont()
757 {
758     NONCLIENTMETRICS mt;
759     mt.cbSize = sizeof(mt);
760     if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(mt), &mt, 0))
761     {
762         ERR("Can't get system parameters !\n");
763         return NULL;
764     }
765     return CreateFontIndirect(&mt.lfMenuFont);
766 
767 }
768 
769 HRESULT CBaseBarSite::FindBandByGUID(REFGUID pGuid, DWORD *pdwBandID)
770 {
771     DWORD                       numBands;
772     DWORD                       i;
773     HRESULT                     hr;
774     REBARBANDINFO               bandInfo;
775     CBarInfo                    *realInfo;
776 
777     hr = EnumBands(-1, &numBands);
778     if (FAILED_UNEXPECTEDLY(hr))
779         return E_FAIL;
780 
781     for(i = 0; i < numBands; i++)
782     {
783         if (FAILED_UNEXPECTEDLY(GetInternalBandInfo(i, &bandInfo)))
784             return E_FAIL;
785         realInfo = (CBarInfo*)bandInfo.lParam;
786         if (IsEqualGUID(pGuid, realInfo->fBarClass))
787         {
788             *pdwBandID = realInfo->fBandID;
789             return S_OK;
790         }
791     }
792     return S_FALSE;
793 }
794 
795 HRESULT CBaseBarSite::ShowBand(DWORD dwBandID)
796 {
797     UINT                        index;
798     CComPtr<IDeskBand>          dockingWindow;
799     HRESULT                     hResult;
800     REBARBANDINFO               bandInfo;
801 
802     // show our band
803     hResult = GetBandObject(dwBandID, IID_PPV_ARG(IDeskBand, &dockingWindow));
804     if (FAILED_UNEXPECTEDLY(hResult))
805         return E_FAIL;
806 
807     hResult = dockingWindow->ShowDW(TRUE);
808 
809     // Hide old band while adding new one
810     if (fCurrentActiveBar && fCurrentActiveBar->fBandID != dwBandID)
811     {
812         DWORD index;
813         index = SendMessage(RB_IDTOINDEX, fCurrentActiveBar->fBandID, 0);
814         if (index != 0xffffffff)
815             SendMessage(RB_SHOWBAND, index, 0);
816     }
817     if (FAILED_UNEXPECTEDLY(hResult))
818         return hResult;
819 
820     // Display the current band
821     index = SendMessage(RB_IDTOINDEX, dwBandID, 0);
822     if (index != 0xffffffff)
823         SendMessage(RB_SHOWBAND, index, 1);
824     if (FAILED_UNEXPECTEDLY(GetInternalBandInfo(index, &bandInfo)))
825         return E_FAIL;
826     fCurrentActiveBar = (CBarInfo*)bandInfo.lParam;
827     return S_OK;
828 }
829 
830 HRESULT CBaseBarSite_CreateInstance(REFIID riid, void **ppv, BOOL bVertical)
831 {
832     return ShellObjectCreatorInit<CBaseBarSite, BOOL>(bVertical, riid, ppv);
833 }
834