aaac501a29b097173cfe8a0b5a6ba00d12781751
[reactos.git] / reactos / dll / win32 / browseui / shellbars / CBandSite.cpp
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
698 if (hWnd == fRebarWindow)
699 {
700 /* FIXME: Just send the message? */
701 *plrResult = SendMessageW(hWnd, uMsg, wParam, lParam);
702 return S_OK;
703 }
704
705 Band = GetBandFromHwnd(hWnd);
706 if (Band != NULL)
707 {
708 return Band->WndEvtHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, plrResult);
709 }
710
711 return E_FAIL;
712 }
713
714 HRESULT STDMETHODCALLTYPE CBandSiteBase::IsWindowOwner(HWND hWnd)
715 {
716 struct BandObject *Band;
717
718 TRACE("(%p, %p)\n", this, hWnd);
719
720 if (fRebarWindow == NULL)
721 return E_FAIL;
722
723 Band = GetBandFromHwnd(hWnd);
724 if (Band != NULL)
725 return S_OK;
726
727 return S_FALSE;
728 }
729
730 HRESULT STDMETHODCALLTYPE CBandSiteBase::GetWindow(HWND *phWnd)
731 {
732 TRACE("(%p, %p)\n", this, phWnd);
733
734 *phWnd = fRebarWindow;
735 if (fRebarWindow != NULL)
736 return S_OK;
737
738 return E_FAIL;
739 }
740
741 HRESULT STDMETHODCALLTYPE CBandSiteBase::ContextSensitiveHelp(BOOL fEnterMode)
742 {
743 FIXME("(%p, %d)\n", this, fEnterMode);
744 return E_NOTIMPL;
745 }
746
747 HRESULT STDMETHODCALLTYPE CBandSiteBase::SetDeskBarSite(IUnknown *pUnk)
748 {
749 HWND hWndParent;
750 HRESULT hRet;
751 DWORD style;
752
753 TRACE("(%p, %p)\n", this, pUnk);
754
755 fOleWindow.Release();
756
757 hRet = pUnk->QueryInterface(IID_PPV_ARG(IOleWindow, &fOleWindow));
758 if (FAILED_UNEXPECTEDLY(hRet))
759 return E_FAIL;
760
761 hRet = fOleWindow->GetWindow(&hWndParent);
762 if (FAILED_UNEXPECTEDLY(hRet))
763 return E_FAIL;
764
765 style = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | RBS_VARHEIGHT | RBS_AUTOSIZE |
766 RBS_BANDBORDERS | CCS_NODIVIDER | /*CCS_NORESIZE |*/ CCS_NOPARENTALIGN;
767
768 fRebarWindow = CreateWindowExW(WS_EX_TOOLWINDOW,
769 REBARCLASSNAMEW,
770 NULL,
771 style,
772 0, 0, 0, 0,
773 hWndParent,
774 NULL,
775 _AtlBaseModule.GetModuleInstance(),
776 NULL);
777 if (fRebarWindow == NULL)
778 {
779 fOleWindow.Release();
780 WARN("IDeskbarClient::SetDeskBarSite() failed to create ReBar control!\n");
781 return E_FAIL;
782 }
783
784 return S_OK;
785 }
786
787 HRESULT STDMETHODCALLTYPE CBandSiteBase::SetModeDBC(DWORD dwMode)
788 {
789 LONG dwStyle;
790 LONG dwPrevStyle;
791
792 TRACE("(%p, %x)\n", this, dwMode);
793
794 if (fRebarWindow == NULL)
795 return E_FAIL;
796
797 dwStyle = dwPrevStyle = GetWindowLongPtr(fRebarWindow, GWL_STYLE);
798 if (dwMode & DBIF_VIEWMODE_VERTICAL)
799 dwStyle |= CCS_VERT;
800
801 if (dwMode & ~DBIF_VIEWMODE_VERTICAL)
802 FIXME("IDeskBarClient::SetModeDBC() unhandled modes: %x\n", dwStyle & ~DBIF_VIEWMODE_VERTICAL);
803
804 if (dwStyle != dwPrevStyle)
805 {
806 SetWindowLongPtr(fRebarWindow, GWL_STYLE, dwPrevStyle);
807 }
808
809 return S_OK;
810 }
811
812 HRESULT STDMETHODCALLTYPE CBandSiteBase::UIActivateDBC(DWORD dwState)
813 {
814 TRACE("(%p, %x)\n", this, dwState);
815
816 if (fRebarWindow == NULL)
817 return E_FAIL;
818
819 ShowWindow(fRebarWindow, (dwState & DBC_SHOW) ? SW_SHOW : SW_HIDE);
820 FIXME("IDeskBarClient::UIActivateDBC() Properly notify bands?\n");
821 return S_OK;
822 }
823
824 HRESULT STDMETHODCALLTYPE CBandSiteBase::GetSize(DWORD unknown1, LPRECT unknown2)
825 {
826 FIXME("(%p, %x, %p)\n", this, unknown1, unknown2);
827 return E_NOTIMPL;
828 }
829
830 HRESULT STDMETHODCALLTYPE CBandSiteBase::QueryStatus(const GUID *pguidCmdGroup,
831 DWORD cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
832 {
833 FIXME("(%p, %p, %u, %p, %p)\n", this, pguidCmdGroup, cCmds, prgCmds, pCmdText);
834 return E_NOTIMPL;
835 }
836
837 HRESULT STDMETHODCALLTYPE CBandSiteBase::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
838 DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
839 {
840 HRESULT hRet = S_OK;
841
842 TRACE("(%p, %p, %u, %u, %p, %p)\n", this, pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn, pvaOut);
843
844 if (fRebarWindow == NULL)
845 return E_FAIL;
846
847 if (IsEqualIID(*pguidCmdGroup, IID_IDeskBand))
848 {
849 switch (nCmdID)
850 {
851 case DBID_BANDINFOCHANGED:
852 if (pvaIn == NULL)
853 hRet = UpdateAllBands();
854 else
855 {
856 /* Update a single band */
857 if (pvaIn->n1.n2.vt == VT_I4)
858 hRet = UpdateBand(pvaIn->n1.n2.n3.lVal);
859 else
860 hRet = E_FAIL;
861 }
862 break;
863
864 case DBID_SHOWONLY:
865 case DBID_MAXIMIZEBAND:
866 case DBID_PUSHCHEVRON:
867 FIXME("IOleCommandTarget::Exec(): Unsupported command ID %d\n", nCmdID);
868 return E_NOTIMPL;
869 default:
870 return E_FAIL;
871 }
872 return hRet;
873 }
874 else
875 WARN("IOleCommandTarget::Exec(): Unsupported command group GUID\n");
876
877 return E_NOTIMPL;
878 }
879
880 HRESULT STDMETHODCALLTYPE CBandSiteBase::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
881 {
882 return E_NOTIMPL;
883 }
884
885 HRESULT STDMETHODCALLTYPE CBandSiteBase::HasFocusIO()
886 {
887 return E_NOTIMPL;
888 }
889
890 HRESULT STDMETHODCALLTYPE CBandSiteBase::TranslateAcceleratorIO(LPMSG lpMsg)
891 {
892 return E_NOTIMPL;
893 }
894
895 HRESULT STDMETHODCALLTYPE CBandSiteBase::OnFocusChangeIS(struct IUnknown *paramC, int param10)
896 {
897 return E_NOTIMPL;
898 }
899
900 HRESULT STDMETHODCALLTYPE CBandSiteBase::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
901 {
902 return E_NOTIMPL;
903 }
904
905 HRESULT STDMETHODCALLTYPE CBandSiteBase::GetClassID(CLSID *pClassID)
906 {
907 return E_NOTIMPL;
908 }
909
910 HRESULT STDMETHODCALLTYPE CBandSiteBase::IsDirty()
911 {
912 return E_NOTIMPL;
913 }
914
915 HRESULT STDMETHODCALLTYPE CBandSiteBase::Load(IStream *pStm)
916 {
917 return E_NOTIMPL;
918 }
919
920 HRESULT STDMETHODCALLTYPE CBandSiteBase::Save(IStream *pStm, BOOL fClearDirty)
921 {
922 return E_NOTIMPL;
923 }
924
925 HRESULT STDMETHODCALLTYPE CBandSiteBase::GetSizeMax(ULARGE_INTEGER *pcbSize)
926 {
927 return E_NOTIMPL;
928 }
929
930 HRESULT STDMETHODCALLTYPE CBandSiteBase::DragEnter(
931 IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
932 {
933 return E_NOTIMPL;
934 }
935
936 HRESULT STDMETHODCALLTYPE CBandSiteBase::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
937 {
938 return E_NOTIMPL;
939 }
940
941 HRESULT STDMETHODCALLTYPE CBandSiteBase::DragLeave()
942 {
943 return E_NOTIMPL;
944 }
945
946 HRESULT STDMETHODCALLTYPE CBandSiteBase::Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
947 {
948 return E_NOTIMPL;
949 }
950
951 HRESULT STDMETHODCALLTYPE CBandSiteBase::LoadFromStreamBS(IStream *, const GUID &, void **)
952 {
953 return E_NOTIMPL;
954 }
955
956 HRESULT STDMETHODCALLTYPE CBandSiteBase::SaveToStreamBS(IUnknown *, IStream *)
957 {
958 return E_NOTIMPL;
959 }
960
961 extern "C"
962 HRESULT WINAPI RSHELL_CBandSite_CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **ppv)
963 {
964 return CBandSite::_CreatorClass::CreateInstance(pUnkOuter, riid, ppv);
965 }