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