xref: /reactos/dll/win32/browseui/basebarsite.cpp (revision 1fec0156)
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