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