[BROWSEUI] Improve CBandSiteBase::OnWinEvent to forward messages correctly to the...
[reactos.git] / 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 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 }