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