1 /*
2  *  Rebar band site
3  *
4  *  Copyright 2007  Herv� Poussineau
5  *  Copyright 2009  Andrew Hill
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "shellbars.h"
23 
24 #ifndef ASSERT
25 #define ASSERT(cond) \
26     if (!(cond)) \
27         ERR ("ASSERTION %s AT %s:%d FAILED!\n", #cond, __FILE__, __LINE__)
28 #endif
29 
30 CBandSiteBase::CBandSiteBase()
31 {
32     fBandsCount = 0;
33     fBandsAllocated = 0;
34     fBands = NULL;
35     fRebarWindow = NULL;
36 }
37 
38 UINT CBandSiteBase::GetBandID(struct BandObject *Band)
39 {
40     return (UINT)(Band - fBands);
41 }
42 
43 struct CBandSiteBase::BandObject *CBandSiteBase::GetBandByID(DWORD dwBandID)
44 {
45     if ((LONG)dwBandID >= fBandsAllocated)
46         return NULL;
47 
48     if (fBands[dwBandID].DeskBand == NULL)
49         return NULL;
50 
51     return &fBands[dwBandID];
52 }
53 
54 void CBandSiteBase::FreeBand(struct BandObject *Band)
55 {
56     ATLASSERT(Band->DeskBand != NULL);
57     ATLASSERT(Band->OleWindow != NULL);
58     ATLASSERT(Band->WndEvtHandler != NULL);
59     Band->DeskBand->Release();
60     Band->OleWindow->Release();
61     Band->WndEvtHandler->Release();
62     memset(Band, 0, sizeof(*Band));
63     fBandsCount--;
64 }
65 
66 DWORD CBandSiteBase::GetBandSiteViewMode()
67 {
68     DWORD                                   dwStyle;
69 
70     /* FIXME: What about DBIF_VIEWMODE_FLOATING and DBIF_VIEWMODE_TRANSPARENT? */
71     dwStyle = GetWindowLongPtr(fRebarWindow, GWL_STYLE);
72 
73     if (dwStyle & CCS_VERT)
74         return DBIF_VIEWMODE_VERTICAL;
75     else
76         return DBIF_VIEWMODE_NORMAL;
77 }
78 
79 VOID CBandSiteBase::BuildRebarBandInfo(struct BandObject *Band, REBARBANDINFOW *prbi)
80 {
81     ZeroMemory(prbi, sizeof(*prbi));
82     prbi->cbSize = sizeof(*prbi);
83 
84     prbi->fMask = RBBIM_ID;
85     prbi->wID = GetBandID(Band);
86 
87     if (Band->dbi.dwMask & DBIM_MINSIZE)
88     {
89         prbi->fMask |= RBBIM_CHILDSIZE;
90         prbi->cxMinChild = Band->dbi.ptMinSize.x;
91         prbi->cyMinChild = Band->dbi.ptMinSize.y;
92     }
93 
94     if (Band->dbi.dwMask & DBIM_MAXSIZE)
95     {
96         prbi->fMask |= RBBIM_CHILDSIZE;
97         prbi->cyMaxChild = Band->dbi.ptMaxSize.y;
98     }
99 
100     if ((Band->dbi.dwMask & (DBIM_INTEGRAL | DBIM_MODEFLAGS)) == (DBIM_INTEGRAL | DBIM_MODEFLAGS) &&
101         (Band->dbi.dwModeFlags & DBIMF_VARIABLEHEIGHT))
102     {
103         prbi->fMask |= RBBIM_CHILDSIZE;
104         prbi->cyIntegral = Band->dbi.ptIntegral.y;
105     }
106 
107     if (Band->dbi.dwMask & DBIM_ACTUAL)
108     {
109         prbi->fMask |= RBBIM_IDEALSIZE | RBBIM_SIZE | RBBIM_CHILDSIZE;
110         prbi->cxIdeal = Band->dbi.ptActual.x;
111         prbi->cx = Band->dbi.ptActual.x;
112         prbi->cyChild = Band->dbi.ptActual.y;
113     }
114 
115     if (Band->dbi.dwMask & DBIM_TITLE)
116     {
117         prbi->fMask |= RBBIM_TEXT;
118         prbi->lpText = Band->dbi.wszTitle;
119         prbi->cch = wcslen(Band->dbi.wszTitle);
120     }
121 
122     if (Band->dbi.dwMask & DBIM_MODEFLAGS)
123     {
124         prbi->fMask |= RBBIM_STYLE;
125 
126         if (Band->dbi.dwModeFlags & DBIMF_FIXED)
127             prbi->fStyle |= RBBS_FIXEDSIZE | RBBS_NOGRIPPER;
128         if (Band->dbi.dwModeFlags & DBIMF_FIXEDBMP)
129             prbi->fStyle |= RBBS_FIXEDBMP;
130         if (Band->dbi.dwModeFlags & DBIMF_VARIABLEHEIGHT)
131             prbi->fStyle |= RBBS_VARIABLEHEIGHT;
132         if (Band->dbi.dwModeFlags & DBIMF_DEBOSSED)
133             prbi->fStyle |= RBBS_CHILDEDGE;
134         if (Band->dbi.dwModeFlags & DBIMF_USECHEVRON)
135             prbi->fStyle |= RBBS_USECHEVRON;
136         if (Band->dbi.dwModeFlags & DBIMF_BREAK)
137             prbi->fStyle |= RBBS_BREAK;
138         if (Band->dbi.dwModeFlags & DBIMF_TOPALIGN)
139             prbi->fStyle |= RBBS_TOPALIGN;
140         if (Band->dbi.dwModeFlags & DBIMF_NOGRIPPER)
141             prbi->fStyle |= RBBS_NOGRIPPER;
142         if (Band->dbi.dwModeFlags & DBIMF_ALWAYSGRIPPER)
143             prbi->fStyle |= RBBS_GRIPPERALWAYS;
144     }
145 
146     if (Band->bHiddenTitle)
147     {
148         prbi->fMask |= RBBIM_STYLE;
149         prbi->fStyle |= RBBS_HIDETITLE;
150     }
151 
152     if ((Band->dbi.dwMask & (DBIM_BKCOLOR | DBIM_MODEFLAGS)) == (DBIM_BKCOLOR | DBIM_MODEFLAGS) &&
153         (Band->dbi.dwModeFlags & DBIMF_BKCOLOR))
154     {
155         prbi->fMask |= RBBIM_COLORS;
156         prbi->clrFore = (COLORREF)(COLOR_WINDOWTEXT + 1);
157         prbi->clrBack = Band->dbi.crBkgnd;
158     }
159 }
160 
161 HRESULT CBandSiteBase::UpdateSingleBand(struct BandObject *Band)
162 {
163     REBARBANDINFOW                          rbi;
164     DWORD                                   dwViewMode;
165     UINT                                    uBand;
166     HRESULT                                 hRet;
167 
168     ZeroMemory(&Band->dbi, sizeof(Band->dbi));
169     Band->dbi.dwMask = DBIM_MINSIZE | DBIM_MAXSIZE | DBIM_INTEGRAL |
170         DBIM_ACTUAL | DBIM_TITLE | DBIM_MODEFLAGS | DBIM_BKCOLOR;
171 
172     dwViewMode = GetBandSiteViewMode();
173 
174     hRet = Band->DeskBand->GetBandInfo((DWORD)GetBandID(Band), dwViewMode, &Band->dbi);
175     if (SUCCEEDED(hRet))
176     {
177         BuildRebarBandInfo(Band, &rbi);
178         if (SUCCEEDED(Band->OleWindow->GetWindow(&rbi.hwndChild)) &&
179             rbi.hwndChild != NULL)
180         {
181             rbi.fMask |= RBBIM_CHILD;
182             WARN ("ReBar band uses child window 0x%p\n", rbi.hwndChild);
183         }
184 
185         uBand = (UINT)SendMessageW(fRebarWindow, RB_IDTOINDEX, (WPARAM)rbi.wID, 0);
186         if (uBand != (UINT)-1)
187         {
188             if (!SendMessageW(fRebarWindow, RB_SETBANDINFOW, (WPARAM)uBand, reinterpret_cast<LPARAM>(&rbi)))
189             {
190                 WARN("Failed to update the rebar band!\n");
191             }
192         }
193         else
194             WARN("Failed to map rebar band id to index!\n");
195 
196     }
197 
198     return hRet;
199 }
200 
201 HRESULT CBandSiteBase::UpdateAllBands()
202 {
203     LONG                                    i;
204     HRESULT                                 hRet;
205 
206     for (i = 0; i < fBandsAllocated; i++)
207     {
208         if (fBands[i].DeskBand != NULL)
209         {
210             hRet = UpdateSingleBand(&fBands[i]);
211             if (FAILED_UNEXPECTEDLY(hRet))
212                 return hRet;
213         }
214     }
215 
216     return S_OK;
217 }
218 
219 HRESULT CBandSiteBase::UpdateBand(DWORD dwBandID)
220 {
221     struct BandObject                       *Band;
222 
223     Band = GetBandByID(dwBandID);
224     if (Band == NULL)
225         return E_FAIL;
226 
227     return UpdateSingleBand(Band);
228 }
229 
230 HRESULT CBandSiteBase::_IsBandDeletable(DWORD dwBandID)
231 {
232     CComPtr<IBandSite> pbs;
233 
234     /* Use QueryInterface so that we get the outer object in case we have one */
235     HRESULT hr = this->QueryInterface(IID_PPV_ARG(IBandSite, &pbs));
236     if (FAILED_UNEXPECTEDLY(hr))
237         return hr;
238 
239     DWORD dwState;
240     hr = pbs->QueryBand(dwBandID, NULL, &dwState, NULL, NULL);
241     if (FAILED_UNEXPECTEDLY(hr))
242         return hr;
243 
244     return ((dwState & BSSF_UNDELETEABLE) != 0) ? S_FALSE : S_OK;
245 }
246 
247 HRESULT CBandSiteBase::OnContextMenu(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plrResult)
248 {
249     /* Find the index fo the band that was clicked */
250     int x = GET_X_LPARAM(lParam);
251     int y = GET_Y_LPARAM(lParam);
252 
253     RBHITTESTINFO htInfo = {{x, y}};
254     ScreenToClient(fRebarWindow, &htInfo.pt);
255     int iBand = SendMessageW(fRebarWindow, RB_HITTEST, 0, (LPARAM)&htInfo);
256     if (iBand < 0)
257     {
258         /* FIXME: what to do here? */
259         return S_OK;
260     }
261 
262     /* Now get the id of the band that was clicked */
263     REBARBANDINFOW bandInfo = {sizeof(bandInfo), RBBIM_ID};
264     SendMessageW(fRebarWindow, RB_GETBANDINFOW, htInfo.iBand, (LPARAM)&bandInfo);
265 
266     /* Finally get the band */
267     DWORD dwBandID = bandInfo.wID;
268     struct BandObject *Band = GetBandByID(dwBandID);
269     if (Band == NULL)
270         return E_FAIL;
271 
272     HMENU hMenu = CreatePopupMenu();
273     if (hMenu == NULL)
274         return E_OUTOFMEMORY;
275 
276     /* Try to load the menu of the band */
277     UINT idBandLast = 0;
278     CComPtr<IContextMenu> pcm;
279     HRESULT hr = Band->DeskBand->QueryInterface(IID_PPV_ARG(IContextMenu, &pcm));
280     if (SUCCEEDED(hr))
281     {
282         hr = pcm->QueryContextMenu(hMenu, 0, 0, UINT_MAX, CMF_NORMAL);
283         if (SUCCEEDED(hr))
284         {
285             idBandLast = HRESULT_CODE(hr);
286         }
287     }
288 
289     /* Load the static part of the menu */
290     HMENU hMenuStatic = LoadMenuW(GetModuleHandleW(L"browseui.dll"), MAKEINTRESOURCEW(IDM_BAND_MENU));
291 
292     if (hMenuStatic)
293     {
294         Shell_MergeMenus(hMenu, hMenuStatic, UINT_MAX, 0, UINT_MAX, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS);
295 
296         ::DestroyMenu(hMenuStatic);
297 
298         hr = _IsBandDeletable(dwBandID);
299         if (FAILED_UNEXPECTEDLY(hr))
300             return hr;
301 
302         /* Remove the close item if it is not deletable */
303         if (hr == S_FALSE || (Band->dbi.dwModeFlags & DBIMF_UNDELETEABLE) != 0)
304             DeleteMenu(hMenu, IDM_BAND_CLOSE, MF_BYCOMMAND);
305 
306         if ((Band->dbi.dwMask & DBIM_TITLE) == 0)
307             DeleteMenu(hMenu, IDM_BAND_TITLE, MF_BYCOMMAND);
308         else
309             CheckMenuItem(hMenu, IDM_BAND_TITLE, Band->bHiddenTitle ? MF_UNCHECKED : MF_CHECKED);
310     }
311 
312     /* TODO: Query the menu of our site */
313 
314     UINT uCommand = ::TrackPopupMenuEx(hMenu, TPM_RETURNCMD, x, y, fRebarWindow, NULL);
315     if (uCommand < idBandLast)
316     {
317         CMINVOKECOMMANDINFO cmi = { sizeof(cmi), 0, fRebarWindow, MAKEINTRESOURCEA(uCommand)};
318         hr = pcm->InvokeCommand(&cmi);
319         if (FAILED_UNEXPECTEDLY(hr))
320             return hr;
321     }
322     else
323     {
324         if (uCommand == IDM_BAND_TITLE)
325         {
326             Band->bHiddenTitle = !Band->bHiddenTitle;
327 
328             hr = UpdateBand(dwBandID);
329             if (FAILED_UNEXPECTEDLY(hr))
330                 return hr;
331         }
332         else if(uCommand == IDM_BAND_CLOSE)
333         {
334             hr = RemoveBand(dwBandID);
335             if (FAILED_UNEXPECTEDLY(hr))
336                 return hr;
337         }
338     }
339 
340     return S_OK;
341 }
342 
343 struct CBandSiteBase::BandObject *CBandSiteBase::GetBandFromHwnd(HWND hwnd)
344 {
345     HRESULT                                 hRet;
346     HWND                                    hWndBand;
347     LONG                                    i;
348 
349     for (i = 0; i < fBandsAllocated; i++)
350     {
351         if (fBands[i].DeskBand != NULL)
352         {
353             ASSERT(fBands[i].OleWindow);
354 
355             hWndBand = NULL;
356             hRet = fBands[i].OleWindow->GetWindow(&hWndBand);
357             if (SUCCEEDED(hRet) && hWndBand == hwnd)
358                 return &fBands[i];
359         }
360     }
361 
362     return NULL;
363 }
364 
365 CBandSiteBase::~CBandSiteBase()
366 {
367 
368     TRACE("destroying %p\n", this);
369 
370     if (fRebarWindow != NULL)
371     {
372         DestroyWindow(fRebarWindow);
373         fRebarWindow = NULL;
374     }
375 
376     if (fBands != NULL)
377     {
378         for (INT i = 0; i < fBandsAllocated; i++)
379         {
380             if (fBands[i].DeskBand != NULL)
381                 FreeBand(&fBands[i]);
382         }
383         CoTaskMemFree(fBands);
384         fBands = NULL;
385     }
386 }
387 
388 HRESULT STDMETHODCALLTYPE CBandSiteBase::AddBand(IUnknown *punk)
389 {
390     LONG                                    NewAllocated;
391     struct BandObject                       *NewBand = NULL;
392     CComPtr<IDeskBand>                      DeskBand;
393     CComPtr<IObjectWithSite>                ObjWithSite;
394     CComPtr<IOleWindow>                     OleWindow;
395     CComPtr<IWinEventHandler>               WndEvtHandler;
396     REBARBANDINFOW                          rbi;
397     HRESULT                                 hRet;
398     UINT                                    uBand;
399 
400     TRACE("(%p, %p)\n", this, punk);
401 
402     if (punk == NULL || fRebarWindow == NULL)
403         return E_FAIL;
404 
405     hRet = punk->QueryInterface(IID_PPV_ARG(IDeskBand, &DeskBand));
406     if (!SUCCEEDED(hRet) || DeskBand == NULL)
407         goto Cleanup;
408     hRet = punk->QueryInterface(IID_PPV_ARG(IObjectWithSite, &ObjWithSite));
409     if (!SUCCEEDED(hRet) || ObjWithSite == NULL)
410         goto Cleanup;
411     hRet = punk->QueryInterface(IID_PPV_ARG(IOleWindow, &OleWindow));
412     if (!SUCCEEDED(hRet) || OleWindow == NULL)
413         goto Cleanup;
414     hRet = punk->QueryInterface(IID_PPV_ARG(IWinEventHandler, &WndEvtHandler));
415     if (!SUCCEEDED(hRet) || WndEvtHandler == NULL)
416         goto Cleanup;
417 
418     hRet = S_OK;
419     if (fBandsAllocated > fBandsCount)
420     {
421         /* Search for a free band object */
422         for (INT i = 0; i < fBandsAllocated; i++)
423         {
424             if (fBands[i].DeskBand == NULL)
425             {
426                 NewBand = &fBands[i];
427                 break;
428             }
429         }
430     }
431     else if (fBandsAllocated > 0)
432     {
433         ASSERT (fBands != NULL);
434 
435         /* Reallocate the band object array */
436         NewAllocated = fBandsAllocated + 8;
437         if (NewAllocated > 0xFFFF)
438             NewAllocated = 0xFFFF;
439         if (NewAllocated == fBandsAllocated)
440         {
441             hRet = E_OUTOFMEMORY;
442             goto Cleanup;
443         }
444 
445 
446         NewBand = static_cast<struct BandObject *>(CoTaskMemAlloc(NewAllocated * sizeof(struct BandObject)));
447         if (NewBand == NULL)
448         {
449             hRet = E_OUTOFMEMORY;
450             goto Cleanup;
451         }
452 
453         /* Copy the old array */
454         memcpy(NewBand, fBands, fBandsAllocated * sizeof(struct BandObject));
455 
456         /* Initialize the added bands */
457         memset(&NewBand[fBandsAllocated], 0, (NewAllocated - fBandsAllocated) * sizeof(struct BandObject));
458 
459         fBandsAllocated = NewAllocated;
460         CoTaskMemFree(fBands);
461         fBands = NewBand;
462     }
463     else
464     {
465         ASSERT(fBands == NULL);
466         ASSERT(fBandsAllocated == 0);
467         ASSERT(fBandsCount == 0);
468 
469         /* Allocate new array */
470         fBands = static_cast<struct BandObject *>(CoTaskMemAlloc(8 * sizeof(struct BandObject)));
471         if (fBands == NULL)
472         {
473             hRet = E_OUTOFMEMORY;
474             goto Cleanup;
475         }
476 
477         /* Initialize the added bands */
478         memset(fBands, 0, 8 * sizeof(struct BandObject));
479 
480         fBandsAllocated += 8;
481         NewBand = &fBands[0];
482     }
483 
484     if (SUCCEEDED(hRet))
485     {
486         ASSERT(NewBand != NULL);
487 
488         fBandsCount++;
489         NewBand->DeskBand = DeskBand.Detach();
490         NewBand->OleWindow = OleWindow.Detach();
491         NewBand->WndEvtHandler = WndEvtHandler.Detach();
492 
493         /* Create the ReBar band */
494         hRet = ObjWithSite->SetSite(static_cast<IOleWindow *>(this));
495         if (SUCCEEDED(hRet))
496         {
497             uBand = 0xffffffff;
498             if (SUCCEEDED(UpdateSingleBand(NewBand)))
499             {
500                 if (NewBand->dbi.dwMask & DBIM_MODEFLAGS)
501                 {
502                     if (NewBand->dbi.dwModeFlags & DBIMF_ADDTOFRONT)
503                         uBand = 0;
504                 }
505             }
506 
507             BuildRebarBandInfo(NewBand, &rbi);
508 
509             if (SUCCEEDED(NewBand->OleWindow->GetWindow(&rbi.hwndChild)) &&
510                 rbi.hwndChild != NULL)
511             {
512                 rbi.fMask |= RBBIM_CHILD;
513                 WARN ("ReBar band uses child window 0x%p\n", rbi.hwndChild);
514             }
515 
516             if (!SendMessageW(fRebarWindow, RB_INSERTBANDW, (WPARAM)uBand, reinterpret_cast<LPARAM>(&rbi)))
517                 return E_FAIL;
518 
519             hRet = (HRESULT)((USHORT)GetBandID(NewBand));
520         }
521         else
522         {
523             WARN("IBandSite::AddBand(): Call to IDeskBand::SetSite() failed: %x\n", hRet);
524 
525             /* Remove the band from the ReBar control */
526             BuildRebarBandInfo(NewBand, &rbi);
527             uBand = (UINT)SendMessageW(fRebarWindow, RB_IDTOINDEX, (WPARAM)rbi.wID, 0);
528             if (uBand != (UINT)-1)
529             {
530                 if (!SendMessageW(fRebarWindow, RB_DELETEBAND, (WPARAM)uBand, 0))
531                 {
532                     ERR("Failed to delete band!\n");
533                 }
534             }
535             else
536                 ERR("Failed to map band id to index!\n");
537 
538             FreeBand(NewBand);
539 
540             hRet = E_FAIL;
541             /* goto Cleanup; */
542         }
543     }
544 Cleanup:
545     return hRet;
546 }
547 
548 HRESULT STDMETHODCALLTYPE CBandSiteBase::EnumBands(UINT uBand, DWORD *pdwBandID)
549 {
550     DWORD                                   i;
551 
552     TRACE("(%p, %u, %p)\n", this, uBand, pdwBandID);
553 
554     if (uBand == 0xffffffff)
555         return (UINT)fBandsCount;
556 
557     if (uBand >= (UINT)fBandsCount)
558         return E_FAIL;
559 
560     for (i = 0; i < (DWORD)fBandsAllocated; i++)
561     {
562         if (fBands[i].DeskBand != NULL)
563         {
564             if (uBand == 0)
565             {
566                 *pdwBandID = i;
567                 return S_OK;
568             }
569 
570             uBand--;
571         }
572     }
573 
574     return E_FAIL;
575 }
576 
577 HRESULT STDMETHODCALLTYPE CBandSiteBase::QueryBand(DWORD dwBandID, IDeskBand **ppstb,
578     DWORD *pdwState, LPWSTR pszName, int cchName)
579 {
580     struct BandObject                       *Band;
581 
582     TRACE("(%p, %u, %p, %p, %p, %d)\n", this, dwBandID, ppstb, pdwState, pszName, cchName);
583 
584     Band = GetBandByID(dwBandID);
585     if (Band == NULL)
586         return E_FAIL;
587 
588     if (ppstb != NULL)
589     {
590         Band->DeskBand->AddRef();
591         *ppstb = Band->DeskBand;
592     }
593 
594     if (pdwState != NULL)
595     {
596         FIXME("IBandSite::QueryBand() requests band state!\n");
597         *pdwState = 0;
598     }
599 
600     if (pszName != NULL && cchName > 0)
601     {
602         FIXME("IBandSite::QueryBand() requests band name!\n");
603         pszName[0] = 0;
604     }
605     return S_OK;
606 }
607 
608 HRESULT STDMETHODCALLTYPE CBandSiteBase::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
609 {
610     struct BandObject                       *Band;
611 
612     TRACE("(%p, %u, %x, %x)\n", this, dwBandID, dwMask, dwState);
613 
614     Band = GetBandByID(dwBandID);
615     if (Band == NULL)
616         return E_FAIL;
617 
618     FIXME("Stub\n");
619     return E_NOTIMPL;
620 }
621 
622 HRESULT STDMETHODCALLTYPE CBandSiteBase::RemoveBand(DWORD dwBandID)
623 {
624     struct BandObject                       *Band;
625     UINT                                    uBand;
626 
627     TRACE("(%p, %u)\n", this, dwBandID);
628 
629     if (fRebarWindow == NULL)
630         return E_FAIL;
631 
632     Band = GetBandByID(dwBandID);
633     if (Band == NULL)
634         return E_FAIL;
635 
636     uBand = (UINT)SendMessageW(fRebarWindow, RB_IDTOINDEX, (WPARAM)GetBandID(Band), 0);
637     if (uBand != (UINT)-1)
638     {
639         if (!SendMessageW(fRebarWindow, RB_DELETEBAND, (WPARAM)uBand, 0))
640         {
641             ERR("Could not delete band!\n");
642         }
643     }
644     else
645         ERR("Could not map band id to index!\n");
646 
647     FreeBand(Band);
648     return S_OK;
649 }
650 
651 HRESULT STDMETHODCALLTYPE CBandSiteBase::GetBandObject(DWORD dwBandID, REFIID riid, VOID **ppv)
652 {
653     struct BandObject                       *Band;
654 
655     TRACE("(%p, %u, %s, %p)\n", this, dwBandID, debugstr_guid(&riid), ppv);
656 
657     Band = GetBandByID(dwBandID);
658     if (Band == NULL)
659     {
660         *ppv = NULL;
661         return E_FAIL;
662     }
663 
664     return Band->DeskBand->QueryInterface(riid, ppv);
665 }
666 
667 HRESULT STDMETHODCALLTYPE CBandSiteBase::SetBandSiteInfo(const BANDSITEINFO *pbsinfo)
668 {
669     FIXME("(%p, %p)\n", this, pbsinfo);
670     return E_NOTIMPL;
671 }
672 
673 HRESULT STDMETHODCALLTYPE CBandSiteBase::GetBandSiteInfo(BANDSITEINFO *pbsinfo)
674 {
675     FIXME("(%p, %p)\n", this, pbsinfo);
676     return E_NOTIMPL;
677 }
678 
679 HRESULT STDMETHODCALLTYPE CBandSiteBase::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plrResult)
680 {
681     struct BandObject                       *Band;
682 
683     TRACE("(%p, %p, %u, %p, %p, %p)\n", this, hWnd, uMsg, wParam, lParam, plrResult);
684 
685     *plrResult = 0;
686     if (fRebarWindow == NULL)
687         return E_FAIL;
688 
689     if (uMsg == WM_CONTEXTMENU)
690     {
691         HRESULT hr = OnContextMenu(hWnd, uMsg, wParam, lParam, plrResult);
692         if (FAILED_UNEXPECTEDLY(hr))
693             return hr;
694 
695         return S_OK;
696     }
697     else if (uMsg == WM_COMMAND && lParam)
698     {
699         hWnd = reinterpret_cast<HWND>(lParam);
700     }
701     else if (uMsg == WM_NOTIFY)
702     {
703         NMHDR* pnmhdr = reinterpret_cast<NMHDR*>(lParam);
704         if (pnmhdr->hwndFrom != fRebarWindow)
705         {
706             hWnd = pnmhdr->hwndFrom;
707         }
708         else
709         {
710             for (int i = 0; i < fBandsAllocated; i++)
711             {
712                 if (fBands[i].WndEvtHandler && fBands[i].OleWindow)
713                 {
714                     HWND hwndBand;
715                     if (SUCCEEDED(fBands[i].OleWindow->GetWindow(&hwndBand)))
716                     {
717                         fBands[i].WndEvtHandler->OnWinEvent(hwndBand, uMsg, wParam, lParam, plrResult);
718                     }
719                 }
720             }
721             return S_OK;
722         }
723     }
724 
725     Band = GetBandFromHwnd(hWnd);
726     if (Band != NULL)
727     {
728         return Band->WndEvtHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, plrResult);
729     }
730 
731     return E_FAIL;
732 }
733 
734 HRESULT STDMETHODCALLTYPE CBandSiteBase::IsWindowOwner(HWND hWnd)
735 {
736     struct BandObject                       *Band;
737 
738     TRACE("(%p, %p)\n", this, hWnd);
739 
740     if (fRebarWindow == NULL)
741         return E_FAIL;
742 
743     Band = GetBandFromHwnd(hWnd);
744     if (Band != NULL)
745         return S_OK;
746 
747     return S_FALSE;
748 }
749 
750 HRESULT STDMETHODCALLTYPE CBandSiteBase::GetWindow(HWND *phWnd)
751 {
752     TRACE("(%p, %p)\n", this, phWnd);
753 
754     *phWnd = fRebarWindow;
755     if (fRebarWindow != NULL)
756         return S_OK;
757 
758     return E_FAIL;
759 }
760 
761 HRESULT STDMETHODCALLTYPE CBandSiteBase::ContextSensitiveHelp(BOOL fEnterMode)
762 {
763     FIXME("(%p, %d)\n", this, fEnterMode);
764     return E_NOTIMPL;
765 }
766 
767 HRESULT STDMETHODCALLTYPE CBandSiteBase::SetDeskBarSite(IUnknown *pUnk)
768 {
769     HWND                                    hWndParent;
770     HRESULT                                 hRet;
771     DWORD                                   style;
772 
773     TRACE("(%p, %p)\n", this, pUnk);
774 
775     fOleWindow.Release();
776 
777     hRet = pUnk->QueryInterface(IID_PPV_ARG(IOleWindow, &fOleWindow));
778     if (FAILED_UNEXPECTEDLY(hRet))
779         return E_FAIL;
780 
781     hRet = fOleWindow->GetWindow(&hWndParent);
782     if (FAILED_UNEXPECTEDLY(hRet))
783         return E_FAIL;
784 
785     style = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | RBS_VARHEIGHT | RBS_AUTOSIZE |
786         RBS_BANDBORDERS | CCS_NODIVIDER | /*CCS_NORESIZE |*/ CCS_NOPARENTALIGN;
787 
788     fRebarWindow = CreateWindowExW(WS_EX_TOOLWINDOW,
789                                    REBARCLASSNAMEW,
790                                    NULL,
791                                    style,
792                                    0, 0, 0, 0,
793                                    hWndParent,
794                                    NULL,
795                                    _AtlBaseModule.GetModuleInstance(),
796                                    NULL);
797     if (fRebarWindow == NULL)
798     {
799         fOleWindow.Release();
800         WARN("IDeskbarClient::SetDeskBarSite() failed to create ReBar control!\n");
801         return E_FAIL;
802     }
803 
804     return S_OK;
805 }
806 
807 HRESULT STDMETHODCALLTYPE CBandSiteBase::SetModeDBC(DWORD dwMode)
808 {
809     LONG                                    dwStyle;
810     LONG                                    dwPrevStyle;
811 
812     TRACE("(%p, %x)\n", this, dwMode);
813 
814     if (fRebarWindow == NULL)
815         return E_FAIL;
816 
817     dwStyle = dwPrevStyle = GetWindowLongPtr(fRebarWindow, GWL_STYLE);
818     if (dwMode & DBIF_VIEWMODE_VERTICAL)
819         dwStyle |= CCS_VERT;
820 
821     if (dwMode & ~DBIF_VIEWMODE_VERTICAL)
822         FIXME("IDeskBarClient::SetModeDBC() unhandled modes: %x\n", dwStyle & ~DBIF_VIEWMODE_VERTICAL);
823 
824     if (dwStyle != dwPrevStyle)
825     {
826         SetWindowLongPtr(fRebarWindow, GWL_STYLE, dwPrevStyle);
827     }
828 
829     return S_OK;
830 }
831 
832 HRESULT STDMETHODCALLTYPE CBandSiteBase::UIActivateDBC(DWORD dwState)
833 {
834     TRACE("(%p, %x)\n", this, dwState);
835 
836     if (fRebarWindow == NULL)
837         return E_FAIL;
838 
839     ShowWindow(fRebarWindow, (dwState & DBC_SHOW) ? SW_SHOW : SW_HIDE);
840     //FIXME: Properly notify bands?
841     return S_OK;
842 }
843 
844 HRESULT STDMETHODCALLTYPE CBandSiteBase::GetSize(DWORD unknown1, LPRECT unknown2)
845 {
846     FIXME("(%p, %x, %p)\n", this, unknown1, unknown2);
847     return E_NOTIMPL;
848 }
849 
850 HRESULT STDMETHODCALLTYPE CBandSiteBase::QueryStatus(const GUID *pguidCmdGroup,
851     DWORD cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
852 {
853     FIXME("(%p, %p, %u, %p, %p)\n", this, pguidCmdGroup, cCmds, prgCmds, pCmdText);
854     return E_NOTIMPL;
855 }
856 
857 HRESULT STDMETHODCALLTYPE CBandSiteBase::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
858     DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
859 {
860     HRESULT                                 hRet = S_OK;
861 
862     TRACE("(%p, %p, %u, %u, %p, %p)\n", this, pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn, pvaOut);
863 
864     if (fRebarWindow == NULL)
865         return E_FAIL;
866 
867     if (IsEqualIID(*pguidCmdGroup, IID_IDeskBand))
868     {
869         switch (nCmdID)
870         {
871             case DBID_BANDINFOCHANGED:
872                 if (pvaIn == NULL)
873                     hRet = UpdateAllBands();
874                 else
875                 {
876                     /* Update a single band */
877                     if (pvaIn->n1.n2.vt == VT_I4)
878                         hRet = UpdateBand(pvaIn->n1.n2.n3.lVal);
879                     else
880                         hRet = E_FAIL;
881                 }
882                 break;
883 
884             case DBID_SHOWONLY:
885             case DBID_MAXIMIZEBAND:
886             case DBID_PUSHCHEVRON:
887                 FIXME("IOleCommandTarget::Exec(): Unsupported command ID %d\n", nCmdID);
888                 return E_NOTIMPL;
889             default:
890                 return E_FAIL;
891         }
892         return hRet;
893     }
894     else
895         WARN("IOleCommandTarget::Exec(): Unsupported command group GUID\n");
896 
897     return E_NOTIMPL;
898 }
899 
900 HRESULT STDMETHODCALLTYPE CBandSiteBase::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
901 {
902     return E_NOTIMPL;
903 }
904 
905 HRESULT STDMETHODCALLTYPE CBandSiteBase::HasFocusIO()
906 {
907     return E_NOTIMPL;
908 }
909 
910 HRESULT STDMETHODCALLTYPE CBandSiteBase::TranslateAcceleratorIO(LPMSG lpMsg)
911 {
912     return E_NOTIMPL;
913 }
914 
915 HRESULT STDMETHODCALLTYPE CBandSiteBase::OnFocusChangeIS(struct IUnknown *paramC, int param10)
916 {
917     return E_NOTIMPL;
918 }
919 
920 HRESULT STDMETHODCALLTYPE CBandSiteBase::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
921 {
922     return E_NOTIMPL;
923 }
924 
925 HRESULT STDMETHODCALLTYPE CBandSiteBase::GetClassID(CLSID *pClassID)
926 {
927     return E_NOTIMPL;
928 }
929 
930 HRESULT STDMETHODCALLTYPE CBandSiteBase::IsDirty()
931 {
932     return E_NOTIMPL;
933 }
934 
935 HRESULT STDMETHODCALLTYPE CBandSiteBase::Load(IStream *pStm)
936 {
937     return E_NOTIMPL;
938 }
939 
940 HRESULT STDMETHODCALLTYPE CBandSiteBase::Save(IStream *pStm, BOOL fClearDirty)
941 {
942     return E_NOTIMPL;
943 }
944 
945 HRESULT STDMETHODCALLTYPE CBandSiteBase::GetSizeMax(ULARGE_INTEGER *pcbSize)
946 {
947     return E_NOTIMPL;
948 }
949 
950 HRESULT STDMETHODCALLTYPE CBandSiteBase::DragEnter(
951     IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
952 {
953     return E_NOTIMPL;
954 }
955 
956 HRESULT STDMETHODCALLTYPE CBandSiteBase::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
957 {
958     return E_NOTIMPL;
959 }
960 
961 HRESULT STDMETHODCALLTYPE CBandSiteBase::DragLeave()
962 {
963     return E_NOTIMPL;
964 }
965 
966 HRESULT STDMETHODCALLTYPE CBandSiteBase::Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
967 {
968     return E_NOTIMPL;
969 }
970 
971 HRESULT STDMETHODCALLTYPE CBandSiteBase::LoadFromStreamBS(IStream *, const GUID &, void **)
972 {
973     return E_NOTIMPL;
974 }
975 
976 HRESULT STDMETHODCALLTYPE CBandSiteBase::SaveToStreamBS(IUnknown *, IStream *)
977 {
978     return E_NOTIMPL;
979 }
980 
981 extern "C"
982 HRESULT WINAPI RSHELL_CBandSite_CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **ppv)
983 {
984     return CBandSite::_CreatorClass::CreateInstance(pUnkOuter, riid, ppv);
985 }
986