xref: /reactos/base/shell/explorer/tbsite.cpp (revision 853b8ebd)
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<IDeskBand> 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     STDMETHODIMP_(ULONG)
AddRef()60     AddRef() override
61     {
62         return InterlockedIncrement(&m_RefCount);
63     }
64 
65     STDMETHODIMP_(ULONG)
Release()66     Release() override
67     {
68         ULONG Ret = InterlockedDecrement(&m_RefCount);
69 
70         if (Ret == 0)
71             delete this;
72 
73         return Ret;
74     }
75 
76     STDMETHODIMP
QueryInterface(IN REFIID riid,OUT LPVOID * ppvObj)77     QueryInterface(IN REFIID riid, OUT LPVOID *ppvObj) override
78     {
79         if (ppvObj == NULL)
80             return E_POINTER;
81 
82         if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IBandSiteHelper))
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 (m_Inner != NULL)
98         {
99             return m_Inner->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:
CTrayBandSite()112     CTrayBandSite() :
113         m_RefCount(0),
114         m_Rebar(NULL)
115     {
116     }
117 
~CTrayBandSite()118     virtual ~CTrayBandSite() { }
119 
120     STDMETHODIMP
OnLoad(IN OUT IStream * pStm,IN REFIID riid,OUT PVOID * pvObj)121     OnLoad(
122         IN OUT IStream *pStm,
123         IN REFIID riid,
124         OUT PVOID *pvObj) override
125     {
126         LARGE_INTEGER liPosZero;
127         ULARGE_INTEGER liCurrent;
128         CLSID clsid;
129         ULONG ulRead;
130         HRESULT hRet;
131 
132         /* NOTE: Callback routine called by the shell while loading the task band
133                  stream. We use it to intercept the default behavior when the task
134                  band is loaded from the stream.
135 
136                  NOTE: riid always points to IID_IUnknown! This is because the shell hasn't
137                  read anything from the stream and therefore doesn't know what CLSID
138                  it's dealing with. We'll have to find it out ourselves by reading
139                  the GUID from the stream. */
140 
141         /* Read the current position of the stream, we'll have to reset it everytime
142            we read a CLSID that's not the task band... */
143         ZeroMemory(&liPosZero, 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(m_TaskBand != NULL);
156                     /* We're trying to load the task band! Let's create it... */
157 
158                     hRet = m_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     STDMETHODIMP
OnSave(IN OUT IUnknown * pUnk,IN OUT IStream * pStm)194     OnSave(
195         IN OUT IUnknown *pUnk,
196         IN OUT IStream *pStm) override
197     {
198         /* NOTE: Callback routine called by the shell while saving the task band
199                  stream. We use it to intercept the default behavior when the task
200                  band is saved to the stream */
201         /* FIXME: Implement */
202         TRACE("IBandSiteStreamCallback::OnSave(0x%p, 0x%p) returns E_NOTIMPL\n", pUnk, pStm);
203         return E_NOTIMPL;
204     }
205 
206     STDMETHODIMP
IsTaskBand(IN IUnknown * punk)207     IsTaskBand(IN IUnknown *punk) override
208     {
209         return IsSameObject(m_BandSite, punk);
210     }
211 
212     STDMETHODIMP
ProcessMessage(IN HWND hWnd,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam,OUT LRESULT * plResult)213     ProcessMessage(
214         IN HWND hWnd,
215         IN UINT uMsg,
216         IN WPARAM wParam,
217         IN LPARAM lParam,
218         OUT LRESULT *plResult) override
219     {
220         HRESULT hRet;
221 
222         ASSERT(m_Rebar != NULL);
223 
224         /* Custom task band behavior */
225         switch (uMsg)
226         {
227         case WM_NOTIFY:
228         {
229             const NMHDR *nmh = (const NMHDR *) lParam;
230 
231             if (nmh->hwndFrom == m_Rebar)
232             {
233                 switch (nmh->code)
234                 {
235                 case NM_NCHITTEST:
236                 {
237                     LPNMMOUSE nmm = (LPNMMOUSE) lParam;
238 
239                     if (nmm->dwHitInfo == RBHT_CLIENT || nmm->dwHitInfo == RBHT_NOWHERE ||
240                         nmm->dwItemSpec == (DWORD_PTR) -1)
241                     {
242                         /* Make the rebar control appear transparent so the user
243                            can drag the tray window */
244                         *plResult = HTTRANSPARENT;
245                     }
246                     return S_OK;
247                 }
248 
249                 case RBN_MINMAX:
250                     /* Deny if an Administrator disabled this "feature" */
251                     *plResult = (SHRestricted(REST_NOMOVINGBAND) != 0);
252                     return S_OK;
253                 }
254             }
255 
256             //TRACE("ITrayBandSite::ProcessMessage: WM_NOTIFY for 0x%p, From: 0x%p, Code: NM_FIRST-%u...\n", hWnd, nmh->hwndFrom, NM_FIRST - nmh->code);
257             break;
258         }
259         }
260 
261         /* Forward to the shell's IWinEventHandler interface to get the default shell behavior! */
262         if (!m_WindowEventHandler)
263             return E_FAIL;
264 
265         /*TRACE("Calling IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p) hWndRebar=0x%p\n", hWnd, uMsg, wParam, lParam, plResult, hWndRebar);*/
266         hRet = m_WindowEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, plResult);
267 
268 #if 0
269         if (FAILED(hRet))
270         {
271             if (uMsg == WM_NOTIFY)
272             {
273                 const NMHDR *nmh = (const NMHDR *) lParam;
274                 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);
275             }
276             else
277             {
278                 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);
279             }
280         }
281 #endif
282 
283         return hRet;
284     }
285 
286     STDMETHODIMP
AddContextMenus(IN HMENU hmenu,IN UINT indexMenu,IN UINT idCmdFirst,IN UINT idCmdLast,IN UINT uFlags,OUT IContextMenu ** ppcm)287     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) override
294     {
295         HRESULT hRet;
296 
297         if (m_ContextMenu == NULL)
298         {
299             /* Cache the context menu so we don't need to CoCreateInstance all the time... */
300             hRet = _CBandSiteMenu_CreateInstance(IID_PPV_ARG(IContextMenu, &m_ContextMenu));
301             if (FAILED_UNEXPECTEDLY(hRet))
302                 return hRet;
303 
304             hRet = IUnknown_SetOwner(m_ContextMenu, (IBandSite*)this);
305             if (FAILED_UNEXPECTEDLY(hRet))
306                 return hRet;
307         }
308 
309         if (ppcm != NULL)
310         {
311             *ppcm = m_ContextMenu;
312             (*ppcm)->AddRef();
313         }
314 
315         /* Add the menu items */
316         hRet = m_ContextMenu->QueryContextMenu(hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
317         if (FAILED_UNEXPECTEDLY(hRet))
318             return hRet;
319 
320         return S_OK;
321     }
322 
323     STDMETHODIMP
Lock(IN BOOL bLock)324     Lock(IN BOOL bLock) override
325     {
326         BOOL bPrevLocked = Locked;
327         BANDSITEINFO bsi;
328         HRESULT hRet;
329 
330         ASSERT(m_BandSite != NULL);
331 
332         if (bPrevLocked != bLock)
333         {
334             Locked = bLock;
335 
336             bsi.dwMask = BSIM_STYLE;
337             bsi.dwStyle = (Locked ? BSIS_LOCKED | BSIS_NOGRIPPER : BSIS_AUTOGRIPPER);
338 
339             hRet = m_BandSite->SetBandSiteInfo(&bsi);
340             if (SUCCEEDED(hRet))
341             {
342                 hRet = Update();
343             }
344 
345             return hRet;
346         }
347 
348         return S_FALSE;
349     }
350 
351     /*******************************************************************/
352 
353     STDMETHODIMP
AddBand(IN IUnknown * punk)354     AddBand(IN IUnknown *punk) override
355     {
356         /* Send the DBID_DELAYINIT command to initialize the band to be added */
357         /* FIXME: Should be delayed */
358         IUnknown_Exec(punk, IID_IDeskBand, DBID_DELAYINIT, 0, NULL, NULL);
359 
360         HRESULT hr = m_BandSite->AddBand(punk);
361         if (FAILED_UNEXPECTEDLY(hr))
362             return hr;
363 
364         VARIANT vThemeName;
365         V_VT(&vThemeName) = VT_BSTR;
366         V_BSTR(&vThemeName) = SysAllocString(L"TaskBar");
367         IUnknown_Exec(punk,
368                       IID_IDeskBand,
369                       DBID_SETWINDOWTHEME,
370                       0,
371                       &vThemeName,
372                       NULL);
373 
374         SysFreeString(V_BSTR(&vThemeName));
375 
376         return S_OK;
377     }
378 
379     STDMETHODIMP
EnumBands(IN UINT uBand,OUT DWORD * pdwBandID)380     EnumBands(
381         IN UINT uBand,
382         OUT DWORD *pdwBandID) override
383     {
384         return m_BandSite->EnumBands(uBand, pdwBandID);
385     }
386 
387     STDMETHODIMP
QueryBand(IN DWORD dwBandID,OUT IDeskBand ** ppstb,OUT DWORD * pdwState,OUT LPWSTR pszName,IN int cchName)388     QueryBand(
389         IN DWORD dwBandID,
390         OUT IDeskBand **ppstb,
391         OUT DWORD *pdwState,
392         OUT LPWSTR pszName,
393         IN int cchName) override
394     {
395         HRESULT hRet;
396         IDeskBand *pstb = NULL;
397 
398         hRet = m_BandSite->QueryBand(
399             dwBandID,
400             &pstb,
401             pdwState,
402             pszName,
403             cchName);
404 
405         if (SUCCEEDED(hRet))
406         {
407             hRet = IsSameObject(pstb, m_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     STDMETHODIMP
SetBandState(IN DWORD dwBandID,IN DWORD dwMask,IN DWORD dwState)430     SetBandState(
431         IN DWORD dwBandID,
432         IN DWORD dwMask,
433         IN DWORD dwState) override
434     {
435         return m_BandSite->SetBandState(dwBandID, dwMask, dwState);
436     }
437 
438     STDMETHODIMP
RemoveBand(IN DWORD dwBandID)439     RemoveBand(IN DWORD dwBandID) override
440     {
441         return m_BandSite->RemoveBand(dwBandID);
442     }
443 
444     STDMETHODIMP
GetBandObject(IN DWORD dwBandID,IN REFIID riid,OUT VOID ** ppv)445     GetBandObject(
446         IN DWORD dwBandID,
447         IN REFIID riid,
448         OUT VOID **ppv) override
449     {
450         return m_BandSite->GetBandObject(dwBandID, riid, ppv);
451     }
452 
453     STDMETHODIMP
SetBandSiteInfo(IN const BANDSITEINFO * pbsinfo)454     SetBandSiteInfo(IN const BANDSITEINFO *pbsinfo) override
455     {
456         return m_BandSite->SetBandSiteInfo(pbsinfo);
457     }
458 
459     STDMETHODIMP
GetBandSiteInfo(IN OUT BANDSITEINFO * pbsinfo)460     GetBandSiteInfo(IN OUT BANDSITEINFO *pbsinfo) override
461     {
462         return m_BandSite->GetBandSiteInfo(pbsinfo);
463     }
464 
HasTaskBand()465     virtual BOOL HasTaskBand()
466     {
467         CComPtr<IPersist> pBand;
468         CLSID BandCLSID;
469         DWORD dwBandID;
470         UINT uBand = 0;
471 
472         /* Enumerate all bands */
473         while (SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID)))
474         {
475             if (dwBandID && SUCCEEDED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IPersist, &pBand))))
476             {
477                 if (SUCCEEDED(pBand->GetClassID(&BandCLSID)))
478                 {
479                     if (IsEqualGUID(BandCLSID, CLSID_ITaskBand))
480                     {
481                         return TRUE;
482                     }
483                 }
484             }
485             uBand++;
486         }
487 
488         return FALSE;
489     }
490 
Update()491     virtual HRESULT Update()
492     {
493         return IUnknown_Exec(m_Inner,
494                 IID_IDeskBand,
495                 DBID_BANDINFOCHANGED,
496                 0,
497                 NULL,
498                 NULL);
499     }
500 
BroadcastOleCommandExec(REFGUID pguidCmdGroup,DWORD nCmdID,DWORD nCmdExecOpt,VARIANTARG * pvaIn,VARIANTARG * pvaOut)501     virtual VOID BroadcastOleCommandExec(REFGUID pguidCmdGroup,
502         DWORD nCmdID,
503         DWORD nCmdExecOpt,
504         VARIANTARG *pvaIn,
505         VARIANTARG *pvaOut)
506     {
507         IOleCommandTarget *pOct;
508         DWORD dwBandID;
509         UINT uBand = 0;
510 
511         /* Enumerate all bands */
512         while (SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID)))
513         {
514             if (SUCCEEDED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IOleCommandTarget, &pOct))))
515             {
516                 /* Execute the command */
517                 pOct->Exec(
518                     &pguidCmdGroup,
519                     nCmdID,
520                     nCmdExecOpt,
521                     pvaIn,
522                     pvaOut);
523 
524                 pOct->Release();
525             }
526 
527             uBand++;
528         }
529     }
530 
FinishInit()531     virtual HRESULT FinishInit()
532     {
533         /* Broadcast the DBID_FINISHINIT command */
534         BroadcastOleCommandExec(IID_IDeskBand, DBID_FINISHINIT, 0, NULL, NULL);
535 
536         return S_OK;
537     }
538 
Show(IN BOOL bShow)539     virtual HRESULT Show(IN BOOL bShow)
540     {
541         CComPtr<IDeskBarClient> pDbc;
542         HRESULT hRet;
543 
544         hRet = m_BandSite->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDbc));
545         if (SUCCEEDED(hRet))
546         {
547             hRet = pDbc->UIActivateDBC(bShow ? DBC_SHOW : DBC_HIDE);
548         }
549 
550         return hRet;
551     }
552 
LoadFromStream(IN OUT IStream * pStm)553     virtual HRESULT LoadFromStream(IN OUT IStream *pStm)
554     {
555         CComPtr<IPersistStream> pPStm;
556         HRESULT hRet;
557 
558         ASSERT(m_BandSite != NULL);
559 
560         /* We implement the undocumented COM interface IBandSiteStreamCallback
561            that the shell will query so that we can intercept and custom-load
562            the task band when it finds the task band's CLSID (which is internal).
563            This way we can prevent the shell from attempting to CoCreateInstance
564            the (internal) task band, resulting in a failure... */
565         hRet = m_BandSite->QueryInterface(IID_PPV_ARG(IPersistStream, &pPStm));
566         if (SUCCEEDED(hRet))
567         {
568             hRet = pPStm->Load(pStm);
569             TRACE("->Load() returned 0x%x\n", hRet);
570         }
571 
572         return hRet;
573     }
574 
GetUserBandsStream(IN DWORD grfMode)575     virtual IStream * GetUserBandsStream(IN DWORD grfMode)
576     {
577         HKEY hkStreams;
578         IStream *Stream = NULL;
579 
580         if (RegCreateKeyW(hkExplorer,
581                           L"Streams",
582                           &hkStreams) == ERROR_SUCCESS)
583         {
584             Stream = SHOpenRegStreamW(hkStreams,
585                                       L"Desktop",
586                                       L"TaskbarWinXP",
587                                       grfMode);
588 
589             RegCloseKey(hkStreams);
590         }
591 
592         return Stream;
593     }
594 
GetDefaultBandsStream(IN DWORD grfMode)595     virtual IStream * GetDefaultBandsStream(IN DWORD grfMode)
596     {
597         HKEY hkStreams;
598         IStream *Stream = NULL;
599 
600         if (RegCreateKeyW(HKEY_LOCAL_MACHINE,
601             L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Streams",
602             &hkStreams) == ERROR_SUCCESS)
603         {
604             Stream = SHOpenRegStreamW(hkStreams,
605                                       L"Desktop",
606                                       L"Default Taskbar",
607                                       grfMode);
608 
609             RegCloseKey(hkStreams);
610         }
611 
612         return Stream;
613     }
614 
Load()615     virtual HRESULT Load()
616     {
617         IStream *pStm;
618         HRESULT hRet;
619 
620         /* Try to load the user's settings */
621         pStm = GetUserBandsStream(STGM_READ);
622         if (pStm != NULL)
623         {
624             hRet = LoadFromStream(pStm);
625 
626             TRACE("Loaded user bands settings: 0x%x\n", hRet);
627             pStm->Release();
628         }
629         else
630             hRet = E_FAIL;
631 
632         /* If the user's settings couldn't be loaded, try with
633            default settings (ie. when the user logs in for the
634            first time! */
635         if (!SUCCEEDED(hRet))
636         {
637             pStm = GetDefaultBandsStream(STGM_READ);
638             if (pStm != NULL)
639             {
640                 hRet = LoadFromStream(pStm);
641 
642                 TRACE("Loaded default user bands settings: 0x%x\n", hRet);
643                 pStm->Release();
644             }
645             else
646                 hRet = E_FAIL;
647         }
648 
649         return hRet;
650     }
651 
_Init(IN ITrayWindow * tray,IN IDeskBand * pTaskBand)652     HRESULT _Init(IN ITrayWindow *tray, IN IDeskBand* pTaskBand)
653     {
654         CComPtr<IDeskBarClient> pDbc;
655         CComPtr<IDeskBand> pDb;
656         CComPtr<IOleWindow> pOw;
657         HRESULT hRet;
658 
659         m_Tray = tray;
660         m_TaskBand = pTaskBand;
661 
662         /* Create the RebarBandSite */
663         hRet = _CBandSite_CreateInstance(static_cast<IBandSite*>(this), IID_PPV_ARG(IUnknown, &m_Inner));
664         if (FAILED_UNEXPECTEDLY(hRet))
665             return hRet;
666 
667         hRet = m_Inner->QueryInterface(IID_PPV_ARG(IBandSite, &m_BandSite));
668         if (FAILED_UNEXPECTEDLY(hRet))
669             return hRet;
670 
671         hRet = m_Inner->QueryInterface(IID_PPV_ARG(IWinEventHandler, &m_WindowEventHandler));
672         if (FAILED_UNEXPECTEDLY(hRet))
673             return hRet;
674 
675         hRet = m_Inner->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDbc));
676         if (FAILED_UNEXPECTEDLY(hRet))
677             return hRet;
678 
679 
680 
681 
682         /* Crete the rebar in the tray */
683         hRet = pDbc->SetDeskBarSite(tray);
684         if (FAILED_UNEXPECTEDLY(hRet))
685             return hRet;
686 
687         hRet = pDbc->GetWindow(&m_Rebar);
688         if (FAILED_UNEXPECTEDLY(hRet))
689             return hRet;
690 
691         SetWindowStyle(m_Rebar, RBS_BANDBORDERS, 0);
692 
693         /* Set the Desk Bar mode to the current one */
694         DWORD dwMode = 0;
695         /* FIXME: We need to set the mode (and update) whenever the user docks
696                   the tray window to another monitor edge! */
697         if (!m_Tray->IsHorizontal())
698             dwMode = DBIF_VIEWMODE_VERTICAL;
699 
700         hRet = pDbc->SetModeDBC(dwMode);
701 
702         /* Load the saved state of the task band site */
703         /* FIXME: We should delay loading shell extensions, also see DBID_DELAYINIT */
704         Load();
705 
706         /* Add the task bar band if it hasn't been added while loading */
707         if (!HasTaskBand())
708         {
709             hRet = m_BandSite->AddBand(m_TaskBand);
710             if (FAILED_UNEXPECTEDLY(hRet))
711                 return hRet;
712         }
713 
714         /* Should we send this after showing it? */
715         Update();
716 
717         /* FIXME: When should we send this? Does anyone care anyway? */
718         FinishInit();
719 
720         /* Activate the band site */
721         Show(TRUE);
722 
723         return S_OK;
724     }
725 };
726 /*******************************************************************/
727 
CTrayBandSite_CreateInstance(IN ITrayWindow * tray,IN IDeskBand * pTaskBand,OUT ITrayBandSite ** pBandSite)728 HRESULT CTrayBandSite_CreateInstance(IN ITrayWindow *tray, IN IDeskBand* pTaskBand, OUT ITrayBandSite** pBandSite)
729 {
730     HRESULT hr;
731 
732     CTrayBandSite * tb = new CTrayBandSite();
733     if (!tb)
734         return E_FAIL;
735 
736     tb->AddRef();
737 
738     hr = tb->_Init(tray, pTaskBand);
739     if (FAILED_UNEXPECTEDLY(hr))
740     {
741         tb->Release();
742         return hr;
743     }
744 
745     *pBandSite = tb;
746 
747     return S_OK;
748 }
749