[EXPLORER-NEW]
[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(
266 hWnd,
267 uMsg,
268 wParam,
269 lParam,
270 plResult);
271 if (FAILED_UNEXPECTEDLY(hRet))
272 {
273 if (uMsg == WM_NOTIFY)
274 {
275 const NMHDR *nmh = (const NMHDR *) lParam;
276 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);
277 }
278 else
279 {
280 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);
281 }
282 }
283
284 return hRet;
285 }
286
287 virtual HRESULT STDMETHODCALLTYPE AddContextMenus(
288 IN HMENU hmenu,
289 IN UINT indexMenu,
290 IN UINT idCmdFirst,
291 IN UINT idCmdLast,
292 IN UINT uFlags,
293 OUT IContextMenu **ppcm)
294 {
295 IShellService *pSs;
296 HRESULT hRet;
297
298 if (ContextMenu == NULL)
299 {
300 /* Cache the context menu so we don't need to CoCreateInstance all the time... */
301 hRet = CoCreateInstance(CLSID_IShellBandSiteMenu, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellService, &pSs));
302 TRACE("CoCreateInstance(CLSID_IShellBandSiteMenu) for IShellService returned: 0x%x\n", hRet);
303 if (!SUCCEEDED(hRet))
304 return hRet;
305
306 hRet = pSs->SetOwner((IBandSite*)this);
307 if (!SUCCEEDED(hRet))
308 {
309 pSs->Release();
310 return hRet;
311 }
312
313 hRet = pSs->QueryInterface(IID_PPV_ARG(IContextMenu, &ContextMenu));
314
315 pSs->Release();
316
317 if (!SUCCEEDED(hRet))
318 return hRet;
319 }
320
321 if (ppcm != NULL)
322 {
323 ContextMenu->AddRef();
324 *ppcm = ContextMenu;
325 }
326
327 /* Add the menu items */
328 return ContextMenu->QueryContextMenu(
329 hmenu,
330 indexMenu,
331 idCmdFirst,
332 idCmdLast,
333 uFlags);
334 }
335
336 virtual HRESULT STDMETHODCALLTYPE Lock(
337 IN BOOL bLock)
338 {
339 BOOL bPrevLocked = Locked;
340 BANDSITEINFO bsi;
341 HRESULT hRet;
342
343 ASSERT(BandSite != NULL);
344
345 if (bPrevLocked != bLock)
346 {
347 Locked = bLock;
348
349 bsi.dwMask = BSIM_STYLE;
350 bsi.dwStyle = (Locked ? BSIS_LOCKED | BSIS_NOGRIPPER : BSIS_AUTOGRIPPER);
351
352 hRet = BandSite->SetBandSiteInfo(&bsi);
353 if (SUCCEEDED(hRet))
354 {
355 hRet = Update();
356 }
357
358 return hRet;
359 }
360
361 return S_FALSE;
362 }
363
364 /*******************************************************************/
365
366 virtual HRESULT STDMETHODCALLTYPE AddBand(
367 IN IUnknown *punk)
368 {
369 IOleCommandTarget *pOct;
370 HRESULT hRet;
371
372 hRet = punk->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pOct));
373 if (SUCCEEDED(hRet))
374 {
375 /* Send the DBID_DELAYINIT command to initialize the band to be added */
376 /* FIXME: Should be delayed */
377 pOct->Exec(
378 &IID_IDeskBand,
379 DBID_DELAYINIT,
380 0,
381 NULL,
382 NULL);
383
384 pOct->Release();
385 }
386
387 return BandSite->AddBand(
388 punk);
389 }
390
391 virtual HRESULT STDMETHODCALLTYPE EnumBands(
392 IN UINT uBand,
393 OUT DWORD *pdwBandID)
394 {
395 return BandSite->EnumBands(
396 uBand,
397 pdwBandID);
398 }
399
400 virtual HRESULT STDMETHODCALLTYPE QueryBand(
401 IN DWORD dwBandID,
402 OUT IDeskBand **ppstb,
403 OUT DWORD *pdwState,
404 OUT LPWSTR pszName,
405 IN int cchName)
406 {
407 HRESULT hRet;
408 IDeskBand *pstb = NULL;
409
410 hRet = BandSite->QueryBand(
411 dwBandID,
412 &pstb,
413 pdwState,
414 pszName,
415 cchName);
416
417 if (SUCCEEDED(hRet))
418 {
419 hRet = IsSameObject(pstb, TaskBand);
420 if (hRet == S_OK)
421 {
422 /* Add the BSSF_UNDELETEABLE flag to pdwState because the task bar band shouldn't be deletable */
423 if (pdwState != NULL)
424 *pdwState |= BSSF_UNDELETEABLE;
425 }
426 else if (!SUCCEEDED(hRet))
427 {
428 pstb->Release();
429 pstb = NULL;
430 }
431
432 if (ppstb != NULL)
433 *ppstb = pstb;
434 }
435 else if (ppstb != NULL)
436 *ppstb = NULL;
437
438 return hRet;
439 }
440
441 virtual HRESULT STDMETHODCALLTYPE SetBandState(
442 IN DWORD dwBandID,
443 IN DWORD dwMask,
444 IN DWORD dwState)
445 {
446 return BandSite->SetBandState(dwBandID, dwMask, dwState);
447 }
448
449 virtual HRESULT STDMETHODCALLTYPE RemoveBand(
450 IN DWORD dwBandID)
451 {
452 return BandSite->RemoveBand(dwBandID);
453 }
454
455 virtual HRESULT STDMETHODCALLTYPE GetBandObject(
456 IN DWORD dwBandID,
457 IN REFIID riid,
458 OUT VOID **ppv)
459 {
460 return BandSite->GetBandObject(dwBandID, riid, ppv);
461 }
462
463 virtual HRESULT STDMETHODCALLTYPE SetBandSiteInfo(
464 IN const BANDSITEINFO *pbsinfo)
465 {
466 return BandSite->SetBandSiteInfo(pbsinfo);
467 }
468
469 virtual HRESULT STDMETHODCALLTYPE GetBandSiteInfo(
470 IN OUT BANDSITEINFO *pbsinfo)
471 {
472 return BandSite->GetBandSiteInfo(pbsinfo);
473 }
474
475 virtual BOOL HasTaskBand()
476 {
477 ASSERT(TaskBand != NULL);
478
479 return SUCCEEDED(TaskBand->GetRebarBandID(
480 NULL));
481 }
482
483 virtual HRESULT AddTaskBand()
484 {
485 #if 0
486 /* FIXME: This is the code for the simple taskbar */
487 IObjectWithSite *pOws;
488 HRESULT hRet;
489
490 hRet = TaskBand->QueryInterface(
491 &IID_IObjectWithSite,
492 (PVOID*) &pOws);
493 if (SUCCEEDED(hRet))
494 {
495 hRet = pOws->SetSite(
496 (IUnknown *)TaskBand);
497
498 pOws->Release();
499 }
500
501 return hRet;
502 #else
503 if (!HasTaskBand())
504 {
505 return BandSite->AddBand(TaskBand);
506 }
507
508 return S_OK;
509 #endif
510 }
511
512 virtual HRESULT Update()
513 {
514 IOleCommandTarget *pOct;
515 HRESULT hRet;
516
517 hRet = punkInner->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pOct));
518 if (SUCCEEDED(hRet))
519 {
520 /* Send the DBID_BANDINFOCHANGED command to update the band site */
521 hRet = pOct->Exec(
522 &IID_IDeskBand,
523 DBID_BANDINFOCHANGED,
524 0,
525 NULL,
526 NULL);
527
528 pOct->Release();
529 }
530
531 return hRet;
532 }
533
534 virtual VOID BroadcastOleCommandExec(const GUID *pguidCmdGroup,
535 DWORD nCmdID,
536 DWORD nCmdExecOpt,
537 VARIANTARG *pvaIn,
538 VARIANTARG *pvaOut)
539 {
540 IOleCommandTarget *pOct;
541 DWORD dwBandID;
542 UINT uBand = 0;
543
544 /* Enumerate all bands */
545 while (SUCCEEDED(BandSite->EnumBands(uBand, &dwBandID)))
546 {
547 if (SUCCEEDED(BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IOleCommandTarget, &pOct))))
548 {
549 /* Execute the command */
550 pOct->Exec(
551 pguidCmdGroup,
552 nCmdID,
553 nCmdExecOpt,
554 pvaIn,
555 pvaOut);
556
557 pOct->Release();
558 }
559
560 uBand++;
561 }
562 }
563
564 virtual HRESULT FinishInit()
565 {
566 /* Broadcast the DBID_FINISHINIT command */
567 BroadcastOleCommandExec(&IID_IDeskBand, DBID_FINISHINIT, 0, NULL, NULL);
568
569 return S_OK;
570 }
571
572 virtual HRESULT Show(
573 IN BOOL bShow)
574 {
575 IDeskBarClient *pDbc;
576 HRESULT hRet;
577
578 hRet = BandSite->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDbc));
579 if (SUCCEEDED(hRet))
580 {
581 hRet = pDbc->UIActivateDBC(
582 bShow ? DBC_SHOW : DBC_HIDE);
583 pDbc->Release();
584 }
585
586 return hRet;
587 }
588
589 virtual HRESULT LoadFromStream(IN OUT IStream *pStm)
590 {
591 IPersistStream *pPStm;
592 HRESULT hRet;
593
594 ASSERT(BandSite != NULL);
595
596 /* We implement the undocumented COM interface IBandSiteStreamCallback
597 that the shell will query so that we can intercept and custom-load
598 the task band when it finds the task band's CLSID (which is internal).
599 This way we can prevent the shell from attempting to CoCreateInstance
600 the (internal) task band, resulting in a failure... */
601 hRet = BandSite->QueryInterface(IID_PPV_ARG(IPersistStream, &pPStm));
602 if (SUCCEEDED(hRet))
603 {
604 hRet = pPStm->Load(
605 pStm);
606 TRACE("->Load() returned 0x%x\n", hRet);
607 pPStm->Release();
608 }
609
610 return hRet;
611 }
612
613 virtual IStream *
614 GetUserBandsStream(IN DWORD grfMode)
615 {
616 HKEY hkStreams;
617 IStream *Stream = NULL;
618
619 if (RegCreateKey(hkExplorer,
620 TEXT("Streams"),
621 &hkStreams) == ERROR_SUCCESS)
622 {
623 Stream = SHOpenRegStream(hkStreams,
624 TEXT("Desktop"),
625 TEXT("TaskbarWinXP"),
626 grfMode);
627
628 RegCloseKey(hkStreams);
629 }
630
631 return Stream;
632 }
633
634 virtual IStream *
635 GetDefaultBandsStream(IN DWORD grfMode)
636 {
637 HKEY hkStreams;
638 IStream *Stream = NULL;
639
640 if (RegCreateKey(HKEY_LOCAL_MACHINE,
641 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Streams"),
642 &hkStreams) == ERROR_SUCCESS)
643 {
644 Stream = SHOpenRegStream(hkStreams,
645 TEXT("Desktop"),
646 TEXT("Default Taskbar"),
647 grfMode);
648
649 RegCloseKey(hkStreams);
650 }
651
652 return Stream;
653 }
654
655 virtual HRESULT Load()
656 {
657 IStream *pStm;
658 HRESULT hRet;
659
660 /* Try to load the user's settings */
661 pStm = GetUserBandsStream(STGM_READ);
662 if (pStm != NULL)
663 {
664 hRet = LoadFromStream(pStm);
665
666 TRACE("Loaded user bands settings: 0x%x\n", hRet);
667 pStm->Release();
668 }
669 else
670 hRet = E_FAIL;
671
672 /* If the user's settings couldn't be loaded, try with
673 default settings (ie. when the user logs in for the
674 first time! */
675 if (!SUCCEEDED(hRet))
676 {
677 pStm = GetDefaultBandsStream(STGM_READ);
678 if (pStm != NULL)
679 {
680 hRet = LoadFromStream(pStm);
681
682 TRACE("Loaded default user bands settings: 0x%x\n", hRet);
683 pStm->Release();
684 }
685 else
686 hRet = E_FAIL;
687 }
688
689 return hRet;
690 }
691
692 HRESULT _Init(IN OUT ITrayWindow *tray, OUT HWND *phWndRebar, OUT HWND *phwndTaskSwitch)
693 {
694 IDeskBarClient *pDbc;
695 IDeskBand *pDb;
696 IOleWindow *pOw;
697 HRESULT hRet;
698
699 *phWndRebar = NULL;
700 *phwndTaskSwitch = NULL;
701
702 Tray = tray;
703
704 /* Create a RebarBandSite provided by the shell */
705 hRet = CoCreateInstance(CLSID_RebarBandSite,
706 static_cast<IBandSite*>(this),
707 CLSCTX_INPROC_SERVER,
708 IID_PPV_ARG(IUnknown, &punkInner));
709 if (!SUCCEEDED(hRet))
710 {
711 return hRet;
712 }
713
714 hRet = punkInner->QueryInterface(IID_PPV_ARG(IBandSite, &BandSite));
715 if (!SUCCEEDED(hRet))
716 {
717 return hRet;
718 }
719
720 hRet = punkInner->QueryInterface(IID_PPV_ARG(IWinEventHandler, &WindowEventHandler));
721 if (!SUCCEEDED(hRet))
722 {
723 return hRet;
724 }
725
726 TaskBand = CreateTaskBand(Tray);
727 if (TaskBand != NULL)
728 {
729 /* Add the task band to the site */
730 hRet = BandSite->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDbc));
731 if (SUCCEEDED(hRet))
732 {
733 hRet = TaskBand->QueryInterface(IID_PPV_ARG(IOleWindow, &pOw));
734 if (SUCCEEDED(hRet))
735 {
736 /* We cause IDeskBarClient to create the rebar control by passing the new
737 task band to it. The band reports the tray window handle as window handle
738 so that IDeskBarClient knows the parent window of the Rebar control that
739 it wants to create. */
740 hRet = pDbc->SetDeskBarSite(pOw);
741
742 if (SUCCEEDED(hRet))
743 {
744 /* The Rebar control is now created, we can query the window handle */
745 hRet = pDbc->GetWindow(&hWndRebar);
746
747 if (SUCCEEDED(hRet))
748 {
749 /* We need to manually remove the RBS_BANDBORDERS style! */
750 SetWindowStyle(hWndRebar, RBS_BANDBORDERS, 0);
751 }
752 }
753
754 pOw->Release();
755 }
756
757 if (SUCCEEDED(hRet))
758 {
759 DWORD dwMode = 0;
760
761 /* Set the Desk Bar mode to the current one */
762
763 /* FIXME: We need to set the mode (and update) whenever the user docks
764 the tray window to another monitor edge! */
765
766 if (!Tray->IsHorizontal())
767 dwMode = DBIF_VIEWMODE_VERTICAL;
768
769 hRet = pDbc->SetModeDBC(dwMode);
770 }
771
772 pDbc->Release();
773 }
774
775 /* Load the saved state of the task band site */
776 /* FIXME: We should delay loading shell extensions, also see DBID_DELAYINIT */
777 Load();
778
779 /* Add the task bar band if it hasn't been added already */
780 hRet = AddTaskBand();
781 if (SUCCEEDED(hRet))
782 {
783 hRet = TaskBand->QueryInterface(IID_PPV_ARG(IDeskBand, &pDb));
784 if (SUCCEEDED(hRet))
785 {
786 hRet = pDb->GetWindow(phwndTaskSwitch);
787 if (!SUCCEEDED(hRet))
788 *phwndTaskSwitch = NULL;
789
790 pDb->Release();
791 }
792 }
793
794 /* Should we send this after showing it? */
795 Update();
796
797 /* FIXME: When should we send this? Does anyone care anyway? */
798 FinishInit();
799
800 /* Activate the band site */
801 Show(
802 TRUE);
803 }
804
805 *phWndRebar = hWndRebar;
806
807 return S_OK;
808 }
809 };
810 /*******************************************************************/
811
812 ITrayBandSite *
813 CreateTrayBandSite(IN OUT ITrayWindow *Tray,
814 OUT HWND *phWndRebar,
815 OUT HWND *phWndTaskSwitch)
816 {
817 HRESULT hr;
818
819 CTrayBandSite * tb = new CTrayBandSite();
820
821 if (!tb)
822 return NULL;
823
824 tb->AddRef();
825
826 hr = tb->_Init(Tray, phWndRebar, phWndTaskSwitch);
827 if (FAILED_UNEXPECTEDLY(hr))
828 tb->Release();
829
830 return tb;
831 }