[EXPLORER] HACK: ignore unimplemented SetBandSiteInfo. Patch by Wim Hueskes. CORE...
[reactos.git] / reactos / base / shell / explorer / tbsite.cpp
1 /*
2 * ReactOS Explorer
3 *
4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "precomp.h"
22
23 #include <shdeprecated.h>
24
25 /*****************************************************************************
26 ** ITrayBandSite ************************************************************
27 *****************************************************************************/
28
29 // WARNING: Can't use ATL for this class due to our ATL not fully supporting the AGGREGATION functions needed for this class to be an "outer" class
30 // it works just fine this way.
31 class CTrayBandSite :
32 public ITrayBandSite,
33 public IBandSite,
34 public IBandSiteStreamCallback
35 /* TODO: IWinEventHandler */
36 {
37 volatile LONG m_RefCount;
38
39 CComPtr<ITrayWindow> m_Tray;
40
41 CComPtr<IUnknown> m_Inner;
42 CComPtr<IBandSite> m_BandSite;
43 CComPtr<ITaskBand> m_TaskBand;
44 CComPtr<IWinEventHandler> m_WindowEventHandler;
45 CComPtr<IContextMenu> m_ContextMenu;
46
47 HWND m_Rebar;
48
49 union
50 {
51 DWORD dwFlags;
52 struct
53 {
54 DWORD Locked : 1;
55 };
56 };
57
58 public:
59
60 virtual ULONG STDMETHODCALLTYPE AddRef()
61 {
62 return InterlockedIncrement(&m_RefCount);
63 }
64
65 virtual ULONG STDMETHODCALLTYPE Release()
66 {
67 ULONG Ret = InterlockedDecrement(&m_RefCount);
68
69 if (Ret == 0)
70 delete this;
71
72 return Ret;
73 }
74
75 virtual HRESULT STDMETHODCALLTYPE QueryInterface(IN REFIID riid, OUT LPVOID *ppvObj)
76 {
77 if (ppvObj == NULL)
78 return E_POINTER;
79
80 if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IBandSiteHelper))
81 {
82 // return IBandSiteStreamCallback's IUnknown
83 *ppvObj = static_cast<IBandSiteStreamCallback*>(this);
84 }
85 else if (IsEqualIID(riid, IID_IBandSite))
86 {
87 *ppvObj = static_cast<IBandSite*>(this);
88 }
89 else if (IsEqualIID(riid, IID_IWinEventHandler))
90 {
91 TRACE("ITaskBandSite: IWinEventHandler queried!\n");
92 *ppvObj = NULL;
93 return E_NOINTERFACE;
94 }
95 else if (m_Inner != NULL)
96 {
97 return m_Inner->QueryInterface(riid, ppvObj);
98 }
99 else
100 {
101 *ppvObj = NULL;
102 return E_NOINTERFACE;
103 }
104
105 AddRef();
106 return S_OK;
107 }
108
109 public:
110 CTrayBandSite() :
111 m_RefCount(0),
112 m_Rebar(NULL)
113 {
114 }
115
116 virtual ~CTrayBandSite() { }
117
118 virtual HRESULT STDMETHODCALLTYPE OnLoad(
119 IN OUT IStream *pStm,
120 IN REFIID riid,
121 OUT PVOID *pvObj)
122 {
123 LARGE_INTEGER liPosZero;
124 ULARGE_INTEGER liCurrent;
125 CLSID clsid;
126 ULONG ulRead;
127 HRESULT hRet;
128
129 /* NOTE: Callback routine called by the shell while loading the task band
130 stream. We use it to intercept the default behavior when the task
131 band is loaded from the stream.
132
133 NOTE: riid always points to IID_IUnknown! This is because the shell hasn't
134 read anything from the stream and therefore doesn't know what CLSID
135 it's dealing with. We'll have to find it out ourselves by reading
136 the GUID from the stream. */
137
138 /* Read the current position of the stream, we'll have to reset it everytime
139 we read a CLSID that's not the task band... */
140 ZeroMemory(&liPosZero, sizeof(liPosZero));
141 hRet = pStm->Seek(liPosZero, STREAM_SEEK_CUR, &liCurrent);
142
143 if (SUCCEEDED(hRet))
144 {
145 /* Now let's read the CLSID from the stream and see if it's our task band */
146 hRet = pStm->Read(&clsid, (ULONG)sizeof(clsid), &ulRead);
147
148 if (SUCCEEDED(hRet) && ulRead == sizeof(clsid))
149 {
150 if (IsEqualGUID(clsid, CLSID_ITaskBand))
151 {
152 ASSERT(m_TaskBand != NULL);
153 /* We're trying to load the task band! Let's create it... */
154
155 hRet = m_TaskBand->QueryInterface(
156 riid,
157 pvObj);
158 if (SUCCEEDED(hRet))
159 {
160 /* Load the stream */
161 TRACE("IBandSiteStreamCallback::OnLoad intercepted the task band CLSID!\n");
162 }
163
164 return hRet;
165 }
166 }
167 }
168
169 /* Reset the position and let the shell do all the work for us */
170 hRet = pStm->Seek(
171 *(LARGE_INTEGER*) &liCurrent,
172 STREAM_SEEK_SET,
173 NULL);
174 if (SUCCEEDED(hRet))
175 {
176 /* Let the shell handle everything else for us :) */
177 hRet = OleLoadFromStream(pStm,
178 riid,
179 pvObj);
180 }
181
182 if (!SUCCEEDED(hRet))
183 {
184 TRACE("IBandSiteStreamCallback::OnLoad(0x%p, 0x%p, 0x%p) returns 0x%x\n", pStm, riid, pvObj, hRet);
185 }
186
187 return hRet;
188 }
189
190 virtual HRESULT STDMETHODCALLTYPE OnSave(
191 IN OUT IUnknown *pUnk,
192 IN OUT IStream *pStm)
193 {
194 /* NOTE: Callback routine called by the shell while saving the task band
195 stream. We use it to intercept the default behavior when the task
196 band is saved to the stream */
197 /* FIXME: Implement */
198 TRACE("IBandSiteStreamCallback::OnSave(0x%p, 0x%p) returns E_NOTIMPL\n", pUnk, pStm);
199 return E_NOTIMPL;
200 }
201
202 virtual HRESULT STDMETHODCALLTYPE IsTaskBand(IN IUnknown *punk)
203 {
204 return IsSameObject(m_BandSite, punk);
205 }
206
207 virtual HRESULT STDMETHODCALLTYPE ProcessMessage(
208 IN HWND hWnd,
209 IN UINT uMsg,
210 IN WPARAM wParam,
211 IN LPARAM lParam,
212 OUT LRESULT *plResult)
213 {
214 HRESULT hRet;
215
216 ASSERT(m_Rebar != NULL);
217
218 /* Custom task band behavior */
219 switch (uMsg)
220 {
221 case WM_NOTIFY:
222 {
223 const NMHDR *nmh = (const NMHDR *) lParam;
224
225 if (nmh->hwndFrom == m_Rebar)
226 {
227 switch (nmh->code)
228 {
229 case NM_NCHITTEST:
230 {
231 LPNMMOUSE nmm = (LPNMMOUSE) lParam;
232
233 if (nmm->dwHitInfo == RBHT_CLIENT || nmm->dwHitInfo == RBHT_NOWHERE ||
234 nmm->dwItemSpec == (DWORD_PTR) -1)
235 {
236 /* Make the rebar control appear transparent so the user
237 can drag the tray window */
238 *plResult = HTTRANSPARENT;
239 }
240 return S_OK;
241 }
242
243 case RBN_MINMAX:
244 /* Deny if an Administrator disabled this "feature" */
245 *plResult = (SHRestricted(REST_NOMOVINGBAND) != 0);
246 return S_OK;
247 }
248 }
249
250 //TRACE("ITrayBandSite::ProcessMessage: WM_NOTIFY for 0x%p, From: 0x%p, Code: NM_FIRST-%u...\n", hWnd, nmh->hwndFrom, NM_FIRST - nmh->code);
251 break;
252 }
253 }
254
255 /* Forward to the shell's IWinEventHandler interface to get the default shell behavior! */
256 if (!m_WindowEventHandler)
257 return E_FAIL;
258
259 /*TRACE("Calling IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p) hWndRebar=0x%p\n", hWnd, uMsg, wParam, lParam, plResult, hWndRebar);*/
260 hRet = m_WindowEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, plResult);
261
262 #if 0
263 if (FAILED(hRet))
264 {
265 if (uMsg == WM_NOTIFY)
266 {
267 const NMHDR *nmh = (const NMHDR *) lParam;
268 ERR("ITrayBandSite->IWinEventHandler::ProcessMessage: WM_NOTIFY for 0x%p, From: 0x%p, Code: NM_FIRST-%u returned 0x%x\n", hWnd, nmh->hwndFrom, NM_FIRST - nmh->code, hRet);
269 }
270 else
271 {
272 ERR("ITrayBandSite->IWinEventHandler::ProcessMessage(0x%p,0x%x,0x%p,0x%p,0x%p->0x%p) returned: 0x%x\n", hWnd, uMsg, wParam, lParam, plResult, *plResult, hRet);
273 }
274 }
275 #endif
276
277 return hRet;
278 }
279
280 virtual HRESULT STDMETHODCALLTYPE AddContextMenus(
281 IN HMENU hmenu,
282 IN UINT indexMenu,
283 IN UINT idCmdFirst,
284 IN UINT idCmdLast,
285 IN UINT uFlags,
286 OUT IContextMenu **ppcm)
287 {
288 if (m_ContextMenu == NULL)
289 {
290 HRESULT hRet;
291 CComPtr<IShellService> pSs;
292
293 /* Cache the context menu so we don't need to CoCreateInstance all the time... */
294 hRet = CoCreateInstance(CLSID_BandSiteMenu, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellService, &pSs));
295 TRACE("CoCreateInstance(CLSID_BandSiteMenu) for IShellService returned: 0x%x\n", hRet);
296 if (!SUCCEEDED(hRet))
297 return hRet;
298
299 hRet = pSs->SetOwner((IBandSite*)this);
300 if (!SUCCEEDED(hRet))
301 {
302 return hRet;
303 }
304
305 hRet = pSs->QueryInterface(IID_PPV_ARG(IContextMenu, &m_ContextMenu));
306
307 if (!SUCCEEDED(hRet))
308 return hRet;
309 }
310
311 if (ppcm != NULL)
312 {
313 m_ContextMenu->AddRef();
314 *ppcm = m_ContextMenu;
315 }
316
317 /* Add the menu items */
318 return m_ContextMenu->QueryContextMenu(hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
319 }
320
321 virtual HRESULT STDMETHODCALLTYPE Lock(IN BOOL bLock)
322 {
323 BOOL bPrevLocked = Locked;
324 BANDSITEINFO bsi;
325 HRESULT hRet;
326
327 ASSERT(m_BandSite != NULL);
328
329 if (bPrevLocked != bLock)
330 {
331 Locked = bLock;
332
333 bsi.dwMask = BSIM_STYLE;
334 bsi.dwStyle = (Locked ? BSIS_LOCKED | BSIS_NOGRIPPER : BSIS_AUTOGRIPPER);
335
336 hRet = m_BandSite->SetBandSiteInfo(&bsi);
337
338 /* HACK for CORE-9809 ! */
339 if (hRet == E_NOTIMPL)
340 hRet = S_OK;
341 else
342 ERR("HACK for CORE-9809 no longer needed!\n");
343
344 if (SUCCEEDED(hRet))
345 {
346 hRet = Update();
347 }
348
349 return hRet;
350 }
351
352 return S_FALSE;
353 }
354
355 /*******************************************************************/
356
357 virtual HRESULT STDMETHODCALLTYPE AddBand(IN IUnknown *punk)
358 {
359 /* Send the DBID_DELAYINIT command to initialize the band to be added */
360 /* FIXME: Should be delayed */
361 IUnknown_Exec(punk, IID_IDeskBand, DBID_DELAYINIT, 0, NULL, NULL);
362
363 return m_BandSite->AddBand(punk);
364 }
365
366 virtual HRESULT STDMETHODCALLTYPE EnumBands(
367 IN UINT uBand,
368 OUT DWORD *pdwBandID)
369 {
370 return m_BandSite->EnumBands(uBand, pdwBandID);
371 }
372
373 virtual HRESULT STDMETHODCALLTYPE QueryBand(
374 IN DWORD dwBandID,
375 OUT IDeskBand **ppstb,
376 OUT DWORD *pdwState,
377 OUT LPWSTR pszName,
378 IN int cchName)
379 {
380 HRESULT hRet;
381 IDeskBand *pstb = NULL;
382
383 hRet = m_BandSite->QueryBand(
384 dwBandID,
385 &pstb,
386 pdwState,
387 pszName,
388 cchName);
389
390 if (SUCCEEDED(hRet))
391 {
392 hRet = IsSameObject(pstb, m_TaskBand);
393 if (hRet == S_OK)
394 {
395 /* Add the BSSF_UNDELETEABLE flag to pdwState because the task bar band shouldn't be deletable */
396 if (pdwState != NULL)
397 *pdwState |= BSSF_UNDELETEABLE;
398 }
399 else if (!SUCCEEDED(hRet))
400 {
401 pstb->Release();
402 pstb = NULL;
403 }
404
405 if (ppstb != NULL)
406 *ppstb = pstb;
407 }
408 else if (ppstb != NULL)
409 *ppstb = NULL;
410
411 return hRet;
412 }
413
414 virtual HRESULT STDMETHODCALLTYPE SetBandState(
415 IN DWORD dwBandID,
416 IN DWORD dwMask,
417 IN DWORD dwState)
418 {
419 return m_BandSite->SetBandState(dwBandID, dwMask, dwState);
420 }
421
422 virtual HRESULT STDMETHODCALLTYPE RemoveBand(
423 IN DWORD dwBandID)
424 {
425 return m_BandSite->RemoveBand(dwBandID);
426 }
427
428 virtual HRESULT STDMETHODCALLTYPE GetBandObject(
429 IN DWORD dwBandID,
430 IN REFIID riid,
431 OUT VOID **ppv)
432 {
433 return m_BandSite->GetBandObject(dwBandID, riid, ppv);
434 }
435
436 virtual HRESULT STDMETHODCALLTYPE SetBandSiteInfo(
437 IN const BANDSITEINFO *pbsinfo)
438 {
439 return m_BandSite->SetBandSiteInfo(pbsinfo);
440 }
441
442 virtual HRESULT STDMETHODCALLTYPE GetBandSiteInfo(
443 IN OUT BANDSITEINFO *pbsinfo)
444 {
445 return m_BandSite->GetBandSiteInfo(pbsinfo);
446 }
447
448 virtual BOOL HasTaskBand()
449 {
450 ASSERT(m_TaskBand != NULL);
451
452 return SUCCEEDED(m_TaskBand->GetRebarBandID(NULL));
453 }
454
455 virtual HRESULT AddTaskBand()
456 {
457 #if 0
458 /* FIXME: This is the code for the simple taskbar */
459 IObjectWithSite *pOws;
460 HRESULT hRet;
461
462 hRet = TaskBand->QueryInterface(
463 &IID_IObjectWithSite,
464 (PVOID*) &pOws);
465 if (SUCCEEDED(hRet))
466 {
467 hRet = pOws->SetSite(
468 (IUnknown *)TaskBand);
469
470 pOws->Release();
471 }
472
473 return hRet;
474 #else
475 if (!HasTaskBand())
476 {
477 return m_BandSite->AddBand(m_TaskBand);
478 }
479
480 return S_OK;
481 #endif
482 }
483
484 virtual HRESULT Update()
485 {
486 return IUnknown_Exec(m_Inner,
487 IID_IDeskBand,
488 DBID_BANDINFOCHANGED,
489 0,
490 NULL,
491 NULL);
492 }
493
494 virtual VOID BroadcastOleCommandExec(REFGUID pguidCmdGroup,
495 DWORD nCmdID,
496 DWORD nCmdExecOpt,
497 VARIANTARG *pvaIn,
498 VARIANTARG *pvaOut)
499 {
500 IOleCommandTarget *pOct;
501 DWORD dwBandID;
502 UINT uBand = 0;
503
504 /* Enumerate all bands */
505 while (SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID)))
506 {
507 if (SUCCEEDED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IOleCommandTarget, &pOct))))
508 {
509 /* Execute the command */
510 pOct->Exec(
511 &pguidCmdGroup,
512 nCmdID,
513 nCmdExecOpt,
514 pvaIn,
515 pvaOut);
516
517 pOct->Release();
518 }
519
520 uBand++;
521 }
522 }
523
524 virtual HRESULT FinishInit()
525 {
526 /* Broadcast the DBID_FINISHINIT command */
527 BroadcastOleCommandExec(IID_IDeskBand, DBID_FINISHINIT, 0, NULL, NULL);
528
529 return S_OK;
530 }
531
532 virtual HRESULT Show(IN BOOL bShow)
533 {
534 CComPtr<IDeskBarClient> pDbc;
535 HRESULT hRet;
536
537 hRet = m_BandSite->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDbc));
538 if (SUCCEEDED(hRet))
539 {
540 hRet = pDbc->UIActivateDBC(bShow ? DBC_SHOW : DBC_HIDE);
541 }
542
543 return hRet;
544 }
545
546 virtual HRESULT LoadFromStream(IN OUT IStream *pStm)
547 {
548 CComPtr<IPersistStream> pPStm;
549 HRESULT hRet;
550
551 ASSERT(m_BandSite != NULL);
552
553 /* We implement the undocumented COM interface IBandSiteStreamCallback
554 that the shell will query so that we can intercept and custom-load
555 the task band when it finds the task band's CLSID (which is internal).
556 This way we can prevent the shell from attempting to CoCreateInstance
557 the (internal) task band, resulting in a failure... */
558 hRet = m_BandSite->QueryInterface(IID_PPV_ARG(IPersistStream, &pPStm));
559 if (SUCCEEDED(hRet))
560 {
561 hRet = pPStm->Load(pStm);
562 TRACE("->Load() returned 0x%x\n", hRet);
563 }
564
565 return hRet;
566 }
567
568 virtual IStream * GetUserBandsStream(IN DWORD grfMode)
569 {
570 HKEY hkStreams;
571 IStream *Stream = NULL;
572
573 if (RegCreateKeyW(hkExplorer,
574 L"Streams",
575 &hkStreams) == ERROR_SUCCESS)
576 {
577 Stream = SHOpenRegStreamW(hkStreams,
578 L"Desktop",
579 L"TaskbarWinXP",
580 grfMode);
581
582 RegCloseKey(hkStreams);
583 }
584
585 return Stream;
586 }
587
588 virtual IStream * GetDefaultBandsStream(IN DWORD grfMode)
589 {
590 HKEY hkStreams;
591 IStream *Stream = NULL;
592
593 if (RegCreateKeyW(HKEY_LOCAL_MACHINE,
594 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Streams",
595 &hkStreams) == ERROR_SUCCESS)
596 {
597 Stream = SHOpenRegStreamW(hkStreams,
598 L"Desktop",
599 L"Default Taskbar",
600 grfMode);
601
602 RegCloseKey(hkStreams);
603 }
604
605 return Stream;
606 }
607
608 virtual HRESULT Load()
609 {
610 IStream *pStm;
611 HRESULT hRet;
612
613 /* Try to load the user's settings */
614 pStm = GetUserBandsStream(STGM_READ);
615 if (pStm != NULL)
616 {
617 hRet = LoadFromStream(pStm);
618
619 TRACE("Loaded user bands settings: 0x%x\n", hRet);
620 pStm->Release();
621 }
622 else
623 hRet = E_FAIL;
624
625 /* If the user's settings couldn't be loaded, try with
626 default settings (ie. when the user logs in for the
627 first time! */
628 if (!SUCCEEDED(hRet))
629 {
630 pStm = GetDefaultBandsStream(STGM_READ);
631 if (pStm != NULL)
632 {
633 hRet = LoadFromStream(pStm);
634
635 TRACE("Loaded default user bands settings: 0x%x\n", hRet);
636 pStm->Release();
637 }
638 else
639 hRet = E_FAIL;
640 }
641
642 return hRet;
643 }
644
645 HRESULT _Init(IN OUT ITrayWindow *tray, OUT HWND *phWndRebar, OUT HWND *phwndTaskSwitch)
646 {
647 CComPtr<IDeskBarClient> pDbc;
648 CComPtr<IDeskBand> pDb;
649 CComPtr<IOleWindow> pOw;
650 HRESULT hRet;
651
652 *phWndRebar = NULL;
653 *phwndTaskSwitch = NULL;
654
655 m_Tray = tray;
656
657 /* Create a RebarBandSite provided by the shell */
658 hRet = CoCreateInstance(CLSID_RebarBandSite,
659 static_cast<IBandSite*>(this),
660 CLSCTX_INPROC_SERVER,
661 IID_PPV_ARG(IUnknown, &m_Inner));
662 if (!SUCCEEDED(hRet))
663 {
664 return hRet;
665 }
666
667 hRet = m_Inner->QueryInterface(IID_PPV_ARG(IBandSite, &m_BandSite));
668 if (!SUCCEEDED(hRet))
669 {
670 return hRet;
671 }
672
673 hRet = m_Inner->QueryInterface(IID_PPV_ARG(IWinEventHandler, &m_WindowEventHandler));
674 if (!SUCCEEDED(hRet))
675 {
676 return hRet;
677 }
678
679 m_TaskBand = CreateTaskBand(m_Tray);
680 if (m_TaskBand != NULL)
681 {
682 /* Add the task band to the site */
683 hRet = m_BandSite->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDbc));
684 if (SUCCEEDED(hRet))
685 {
686 hRet = m_TaskBand->QueryInterface(IID_PPV_ARG(IOleWindow, &pOw));
687 if (SUCCEEDED(hRet))
688 {
689 /* We cause IDeskBarClient to create the rebar control by passing the new
690 task band to it. The band reports the tray window handle as window handle
691 so that IDeskBarClient knows the parent window of the Rebar control that
692 it wants to create. */
693 hRet = pDbc->SetDeskBarSite(pOw);
694
695 if (SUCCEEDED(hRet))
696 {
697 /* The Rebar control is now created, we can query the window handle */
698 hRet = pDbc->GetWindow(&m_Rebar);
699
700 if (SUCCEEDED(hRet))
701 {
702 /* We need to manually remove the RBS_BANDBORDERS style! */
703 SetWindowStyle(m_Rebar, RBS_BANDBORDERS, 0);
704 }
705 }
706 }
707
708 if (SUCCEEDED(hRet))
709 {
710 DWORD dwMode = 0;
711
712 /* Set the Desk Bar mode to the current one */
713
714 /* FIXME: We need to set the mode (and update) whenever the user docks
715 the tray window to another monitor edge! */
716
717 if (!m_Tray->IsHorizontal())
718 dwMode = DBIF_VIEWMODE_VERTICAL;
719
720 hRet = pDbc->SetModeDBC(dwMode);
721 }
722
723 pDbc->Release();
724 }
725
726 /* Load the saved state of the task band site */
727 /* FIXME: We should delay loading shell extensions, also see DBID_DELAYINIT */
728 Load();
729
730 /* Add the task bar band if it hasn't been added already */
731 hRet = AddTaskBand();
732 if (SUCCEEDED(hRet))
733 {
734 hRet = m_TaskBand->QueryInterface(IID_PPV_ARG(IDeskBand, &pDb));
735 if (SUCCEEDED(hRet))
736 {
737 hRet = pDb->GetWindow(phwndTaskSwitch);
738 if (!SUCCEEDED(hRet))
739 *phwndTaskSwitch = NULL;
740 }
741 }
742
743 /* Should we send this after showing it? */
744 Update();
745
746 /* FIXME: When should we send this? Does anyone care anyway? */
747 FinishInit();
748
749 /* Activate the band site */
750 Show(
751 TRUE);
752 }
753
754 *phWndRebar = m_Rebar;
755
756 return S_OK;
757 }
758 };
759 /*******************************************************************/
760
761 ITrayBandSite*
762 CreateTrayBandSite(IN OUT ITrayWindow *Tray,
763 OUT HWND *phWndRebar,
764 OUT HWND *phWndTaskSwitch)
765 {
766 HRESULT hr;
767
768 CTrayBandSite * tb = new CTrayBandSite();
769
770 if (!tb)
771 return NULL;
772
773 tb->AddRef();
774
775 hr = tb->_Init(Tray, phWndRebar, phWndTaskSwitch);
776 if (FAILED_UNEXPECTEDLY(hr))
777 tb->Release();
778
779 return tb;
780 }