xref: /reactos/base/shell/explorer/tbsite.cpp (revision 8e659192)
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 
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         HRESULT hRet;
289 
290         if (m_ContextMenu == NULL)
291         {
292             /* Cache the context menu so we don't need to CoCreateInstance all the time... */
293             hRet = _CBandSiteMenu_CreateInstance(IID_PPV_ARG(IContextMenu, &m_ContextMenu));
294             if (FAILED_UNEXPECTEDLY(hRet))
295                 return hRet;
296 
297             hRet = IUnknown_SetOwner(m_ContextMenu, (IBandSite*)this);
298             if (FAILED_UNEXPECTEDLY(hRet))
299                 return hRet;
300         }
301 
302         if (ppcm != NULL)
303         {
304             m_ContextMenu->AddRef();
305             *ppcm = m_ContextMenu;
306         }
307 
308         /* Add the menu items */
309         hRet = m_ContextMenu->QueryContextMenu(hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
310         if (FAILED_UNEXPECTEDLY(hRet))
311             return hRet;
312 
313         return S_OK;
314     }
315 
316     virtual HRESULT STDMETHODCALLTYPE Lock(IN BOOL bLock)
317     {
318         BOOL bPrevLocked = Locked;
319         BANDSITEINFO bsi;
320         HRESULT hRet;
321 
322         ASSERT(m_BandSite != NULL);
323 
324         if (bPrevLocked != bLock)
325         {
326             Locked = bLock;
327 
328             bsi.dwMask = BSIM_STYLE;
329             bsi.dwStyle = (Locked ? BSIS_LOCKED | BSIS_NOGRIPPER : BSIS_AUTOGRIPPER);
330 
331             hRet = m_BandSite->SetBandSiteInfo(&bsi);
332 
333             /* HACK for CORE-9809 ! */
334             if (hRet == E_NOTIMPL)
335                 hRet = S_OK;
336             else
337                 ERR("HACK for CORE-9809 no longer needed!\n");
338 
339             if (SUCCEEDED(hRet))
340             {
341                 hRet = Update();
342             }
343 
344             return hRet;
345         }
346 
347         return S_FALSE;
348     }
349 
350     /*******************************************************************/
351 
352     virtual HRESULT STDMETHODCALLTYPE AddBand(IN IUnknown *punk)
353     {
354         /* Send the DBID_DELAYINIT command to initialize the band to be added */
355         /* FIXME: Should be delayed */
356         IUnknown_Exec(punk, IID_IDeskBand, DBID_DELAYINIT, 0, NULL, NULL);
357 
358         HRESULT hr = m_BandSite->AddBand(punk);
359         if (FAILED_UNEXPECTEDLY(hr))
360             return hr;
361 
362         VARIANT vThemeName;
363         V_VT(&vThemeName) = VT_BSTR;
364         V_BSTR(&vThemeName) = SysAllocString(L"TaskBar");
365         IUnknown_Exec(punk,
366                       IID_IDeskBand,
367                       DBID_SETWINDOWTHEME,
368                       0,
369                       &vThemeName,
370                       NULL);
371 
372         SysFreeString(V_BSTR(&vThemeName));
373 
374         return S_OK;
375     }
376 
377     virtual HRESULT STDMETHODCALLTYPE EnumBands(
378         IN UINT uBand,
379         OUT DWORD *pdwBandID)
380     {
381         return m_BandSite->EnumBands(uBand, pdwBandID);
382     }
383 
384     virtual HRESULT STDMETHODCALLTYPE QueryBand(
385         IN DWORD dwBandID,
386         OUT IDeskBand **ppstb,
387         OUT DWORD *pdwState,
388         OUT LPWSTR pszName,
389         IN int cchName)
390     {
391         HRESULT hRet;
392         IDeskBand *pstb = NULL;
393 
394         hRet = m_BandSite->QueryBand(
395             dwBandID,
396             &pstb,
397             pdwState,
398             pszName,
399             cchName);
400 
401         if (SUCCEEDED(hRet))
402         {
403             hRet = IsSameObject(pstb, m_TaskBand);
404             if (hRet == S_OK)
405             {
406                 /* Add the BSSF_UNDELETEABLE flag to pdwState because the task bar band shouldn't be deletable */
407                 if (pdwState != NULL)
408                     *pdwState |= BSSF_UNDELETEABLE;
409             }
410             else if (!SUCCEEDED(hRet))
411             {
412                 pstb->Release();
413                 pstb = NULL;
414             }
415 
416             if (ppstb != NULL)
417                 *ppstb = pstb;
418         }
419         else if (ppstb != NULL)
420             *ppstb = NULL;
421 
422         return hRet;
423     }
424 
425     virtual HRESULT STDMETHODCALLTYPE SetBandState(
426         IN DWORD dwBandID,
427         IN DWORD dwMask,
428         IN DWORD dwState)
429     {
430         return m_BandSite->SetBandState(dwBandID, dwMask, dwState);
431     }
432 
433     virtual HRESULT STDMETHODCALLTYPE RemoveBand(
434         IN DWORD dwBandID)
435     {
436         return m_BandSite->RemoveBand(dwBandID);
437     }
438 
439     virtual HRESULT STDMETHODCALLTYPE GetBandObject(
440         IN DWORD dwBandID,
441         IN REFIID riid,
442         OUT VOID **ppv)
443     {
444         return m_BandSite->GetBandObject(dwBandID, riid, ppv);
445     }
446 
447     virtual HRESULT STDMETHODCALLTYPE SetBandSiteInfo(
448         IN const BANDSITEINFO *pbsinfo)
449     {
450         return m_BandSite->SetBandSiteInfo(pbsinfo);
451     }
452 
453     virtual HRESULT STDMETHODCALLTYPE GetBandSiteInfo(
454         IN OUT BANDSITEINFO *pbsinfo)
455     {
456         return m_BandSite->GetBandSiteInfo(pbsinfo);
457     }
458 
459     virtual BOOL HasTaskBand()
460     {
461         CComPtr<IPersist> pBand;
462         CLSID BandCLSID;
463         DWORD dwBandID;
464         UINT uBand = 0;
465 
466         /* Enumerate all bands */
467         while (SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID)))
468         {
469             if (SUCCEEDED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IPersist, &pBand))))
470             {
471                 if (SUCCEEDED(pBand->GetClassID(&BandCLSID)))
472                 {
473                     if (IsEqualGUID(BandCLSID, CLSID_ITaskBand))
474                     {
475                         return TRUE;
476                     }
477                 }
478             }
479             uBand++;
480         }
481 
482         return FALSE;
483     }
484 
485     virtual HRESULT Update()
486     {
487         return IUnknown_Exec(m_Inner,
488                 IID_IDeskBand,
489                 DBID_BANDINFOCHANGED,
490                 0,
491                 NULL,
492                 NULL);
493     }
494 
495     virtual VOID BroadcastOleCommandExec(REFGUID pguidCmdGroup,
496         DWORD nCmdID,
497         DWORD nCmdExecOpt,
498         VARIANTARG *pvaIn,
499         VARIANTARG *pvaOut)
500     {
501         IOleCommandTarget *pOct;
502         DWORD dwBandID;
503         UINT uBand = 0;
504 
505         /* Enumerate all bands */
506         while (SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID)))
507         {
508             if (SUCCEEDED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IOleCommandTarget, &pOct))))
509             {
510                 /* Execute the command */
511                 pOct->Exec(
512                     &pguidCmdGroup,
513                     nCmdID,
514                     nCmdExecOpt,
515                     pvaIn,
516                     pvaOut);
517 
518                 pOct->Release();
519             }
520 
521             uBand++;
522         }
523     }
524 
525     virtual HRESULT FinishInit()
526     {
527         /* Broadcast the DBID_FINISHINIT command */
528         BroadcastOleCommandExec(IID_IDeskBand, DBID_FINISHINIT, 0, NULL, NULL);
529 
530         return S_OK;
531     }
532 
533     virtual HRESULT Show(IN BOOL bShow)
534     {
535         CComPtr<IDeskBarClient> pDbc;
536         HRESULT hRet;
537 
538         hRet = m_BandSite->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDbc));
539         if (SUCCEEDED(hRet))
540         {
541             hRet = pDbc->UIActivateDBC(bShow ? DBC_SHOW : DBC_HIDE);
542         }
543 
544         return hRet;
545     }
546 
547     virtual HRESULT LoadFromStream(IN OUT IStream *pStm)
548     {
549         CComPtr<IPersistStream> pPStm;
550         HRESULT hRet;
551 
552         ASSERT(m_BandSite != NULL);
553 
554         /* We implement the undocumented COM interface IBandSiteStreamCallback
555            that the shell will query so that we can intercept and custom-load
556            the task band when it finds the task band's CLSID (which is internal).
557            This way we can prevent the shell from attempting to CoCreateInstance
558            the (internal) task band, resulting in a failure... */
559         hRet = m_BandSite->QueryInterface(IID_PPV_ARG(IPersistStream, &pPStm));
560         if (SUCCEEDED(hRet))
561         {
562             hRet = pPStm->Load(pStm);
563             TRACE("->Load() returned 0x%x\n", hRet);
564         }
565 
566         return hRet;
567     }
568 
569     virtual IStream * GetUserBandsStream(IN DWORD grfMode)
570     {
571         HKEY hkStreams;
572         IStream *Stream = NULL;
573 
574         if (RegCreateKeyW(hkExplorer,
575                           L"Streams",
576                           &hkStreams) == ERROR_SUCCESS)
577         {
578             Stream = SHOpenRegStreamW(hkStreams,
579                                       L"Desktop",
580                                       L"TaskbarWinXP",
581                                       grfMode);
582 
583             RegCloseKey(hkStreams);
584         }
585 
586         return Stream;
587     }
588 
589     virtual IStream * GetDefaultBandsStream(IN DWORD grfMode)
590     {
591         HKEY hkStreams;
592         IStream *Stream = NULL;
593 
594         if (RegCreateKeyW(HKEY_LOCAL_MACHINE,
595             L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Streams",
596             &hkStreams) == ERROR_SUCCESS)
597         {
598             Stream = SHOpenRegStreamW(hkStreams,
599                                       L"Desktop",
600                                       L"Default Taskbar",
601                                       grfMode);
602 
603             RegCloseKey(hkStreams);
604         }
605 
606         return Stream;
607     }
608 
609     virtual HRESULT Load()
610     {
611         IStream *pStm;
612         HRESULT hRet;
613 
614         /* Try to load the user's settings */
615         pStm = GetUserBandsStream(STGM_READ);
616         if (pStm != NULL)
617         {
618             hRet = LoadFromStream(pStm);
619 
620             TRACE("Loaded user bands settings: 0x%x\n", hRet);
621             pStm->Release();
622         }
623         else
624             hRet = E_FAIL;
625 
626         /* If the user's settings couldn't be loaded, try with
627            default settings (ie. when the user logs in for the
628            first time! */
629         if (!SUCCEEDED(hRet))
630         {
631             pStm = GetDefaultBandsStream(STGM_READ);
632             if (pStm != NULL)
633             {
634                 hRet = LoadFromStream(pStm);
635 
636                 TRACE("Loaded default user bands settings: 0x%x\n", hRet);
637                 pStm->Release();
638             }
639             else
640                 hRet = E_FAIL;
641         }
642 
643         return hRet;
644     }
645 
646     HRESULT _Init(IN ITrayWindow *tray, IN IDeskBand* pTaskBand)
647     {
648         CComPtr<IDeskBarClient> pDbc;
649         CComPtr<IDeskBand> pDb;
650         CComPtr<IOleWindow> pOw;
651         HRESULT hRet;
652 
653         m_Tray = tray;
654         m_TaskBand = pTaskBand;
655 
656         /* Create the RebarBandSite */
657         hRet = _CBandSite_CreateInstance(static_cast<IBandSite*>(this), IID_PPV_ARG(IUnknown, &m_Inner));
658         if (FAILED_UNEXPECTEDLY(hRet))
659             return hRet;
660 
661         hRet = m_Inner->QueryInterface(IID_PPV_ARG(IBandSite, &m_BandSite));
662         if (FAILED_UNEXPECTEDLY(hRet))
663             return hRet;
664 
665         hRet = m_Inner->QueryInterface(IID_PPV_ARG(IWinEventHandler, &m_WindowEventHandler));
666         if (FAILED_UNEXPECTEDLY(hRet))
667             return hRet;
668 
669         hRet = m_Inner->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDbc));
670         if (FAILED_UNEXPECTEDLY(hRet))
671             return hRet;
672 
673 
674 
675 
676         /* Crete the rebar in the tray */
677         hRet = pDbc->SetDeskBarSite(tray);
678         if (FAILED_UNEXPECTEDLY(hRet))
679             return hRet;
680 
681         hRet = pDbc->GetWindow(&m_Rebar);
682         if (FAILED_UNEXPECTEDLY(hRet))
683             return hRet;
684 
685         SetWindowStyle(m_Rebar, RBS_BANDBORDERS, 0);
686 
687         /* Set the Desk Bar mode to the current one */
688         DWORD dwMode = 0;
689         /* FIXME: We need to set the mode (and update) whenever the user docks
690                   the tray window to another monitor edge! */
691         if (!m_Tray->IsHorizontal())
692             dwMode = DBIF_VIEWMODE_VERTICAL;
693 
694         hRet = pDbc->SetModeDBC(dwMode);
695 
696         /* Load the saved state of the task band site */
697         /* FIXME: We should delay loading shell extensions, also see DBID_DELAYINIT */
698         Load();
699 
700         /* Add the task bar band if it hasn't been added while loading */
701         if (!HasTaskBand())
702         {
703             hRet = m_BandSite->AddBand(m_TaskBand);
704             if (FAILED_UNEXPECTEDLY(hRet))
705                 return hRet;
706         }
707 
708         /* Should we send this after showing it? */
709         Update();
710 
711         /* FIXME: When should we send this? Does anyone care anyway? */
712         FinishInit();
713 
714         /* Activate the band site */
715         Show(TRUE);
716 
717         return S_OK;
718     }
719 };
720 /*******************************************************************/
721 
722 HRESULT CTrayBandSite_CreateInstance(IN ITrayWindow *tray, IN IDeskBand* pTaskBand, OUT ITrayBandSite** pBandSite)
723 {
724     HRESULT hr;
725 
726     CTrayBandSite * tb = new CTrayBandSite();
727     if (!tb)
728         return E_FAIL;
729 
730     tb->AddRef();
731 
732     hr = tb->_Init(tray, pTaskBand);
733     if (FAILED_UNEXPECTEDLY(hr))
734     {
735         tb->Release();
736         return hr;
737     }
738 
739     *pBandSite = tb;
740 
741     return S_OK;
742 }
743