Partial merge of condrv_restructure branch r65657.
[reactos.git] / reactos / base / shell / explorer / 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 /*****************************************************************************
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<ITaskBand> 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,
141 sizeof(liPosZero));
142 hRet = pStm->Seek(liPosZero, STREAM_SEEK_CUR, &liCurrent);
143
144 if (SUCCEEDED(hRet))
145 {
146 /* Now let's read the CLSID from the stream and see if it's our task band */
147 hRet = pStm->Read(&clsid, (ULONG)sizeof(clsid), &ulRead);
148
149 if (SUCCEEDED(hRet) && ulRead == sizeof(clsid))
150 {
151 if (IsEqualGUID(clsid, CLSID_ITaskBand))
152 {
153 ASSERT(m_TaskBand != NULL);
154 /* We're trying to load the task band! Let's create it... */
155
156 hRet = m_TaskBand->QueryInterface(
157 riid,
158 pvObj);
159 if (SUCCEEDED(hRet))
160 {
161 /* Load the stream */
162 TRACE("IBandSiteStreamCallback::OnLoad intercepted the task band CLSID!\n");
163 }
164
165 return hRet;
166 }
167 }
168 }
169
170 /* Reset the position and let the shell do all the work for us */
171 hRet = pStm->Seek(
172 *(LARGE_INTEGER*) &liCurrent,
173 STREAM_SEEK_SET,
174 NULL);
175 if (SUCCEEDED(hRet))
176 {
177 /* Let the shell handle everything else for us :) */
178 hRet = OleLoadFromStream(pStm,
179 riid,
180 pvObj);
181 }
182
183 if (!SUCCEEDED(hRet))
184 {
185 TRACE("IBandSiteStreamCallback::OnLoad(0x%p, 0x%p, 0x%p) returns 0x%x\n", pStm, riid, pvObj, hRet);
186 }
187
188 return hRet;
189 }
190
191 virtual HRESULT STDMETHODCALLTYPE OnSave(
192 IN OUT IUnknown *pUnk,
193 IN OUT IStream *pStm)
194 {
195 /* NOTE: Callback routine called by the shell while saving the task band
196 stream. We use it to intercept the default behavior when the task
197 band is saved to the stream */
198 /* FIXME: Implement */
199 TRACE("IBandSiteStreamCallback::OnSave(0x%p, 0x%p) returns E_NOTIMPL\n", pUnk, pStm);
200 return E_NOTIMPL;
201 }
202
203 virtual HRESULT STDMETHODCALLTYPE IsTaskBand(IN IUnknown *punk)
204 {
205 return IsSameObject(m_BandSite, punk);
206 }
207
208 virtual HRESULT STDMETHODCALLTYPE ProcessMessage(
209 IN HWND hWnd,
210 IN UINT uMsg,
211 IN WPARAM wParam,
212 IN LPARAM lParam,
213 OUT LRESULT *plResult)
214 {
215 HRESULT hRet;
216
217 ASSERT(m_Rebar != NULL);
218
219 /* Custom task band behavior */
220 switch (uMsg)
221 {
222 case WM_NOTIFY:
223 {
224 const NMHDR *nmh = (const NMHDR *) lParam;
225
226 if (nmh->hwndFrom == m_Rebar)
227 {
228 switch (nmh->code)
229 {
230 case NM_NCHITTEST:
231 {
232 LPNMMOUSE nmm = (LPNMMOUSE) lParam;
233
234 if (nmm->dwHitInfo == RBHT_CLIENT || nmm->dwHitInfo == RBHT_NOWHERE ||
235 nmm->dwItemSpec == (DWORD_PTR) -1)
236 {
237 /* Make the rebar control appear transparent so the user
238 can drag the tray window */
239 *plResult = HTTRANSPARENT;
240 }
241 return S_OK;
242 }
243
244 case RBN_MINMAX:
245 /* Deny if an Administrator disabled this "feature" */
246 *plResult = (SHRestricted(REST_NOMOVINGBAND) != 0);
247 return S_OK;
248 }
249 }
250
251 //TRACE("ITrayBandSite::ProcessMessage: WM_NOTIFY for 0x%p, From: 0x%p, Code: NM_FIRST-%u...\n", hWnd, nmh->hwndFrom, NM_FIRST - nmh->code);
252 break;
253 }
254 }
255
256 /* Forward to the shell's IWinEventHandler interface to get the default shell behavior! */
257 if (!m_WindowEventHandler)
258 return E_FAIL;
259
260 /*TRACE("Calling IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p) hWndRebar=0x%p\n", hWnd, uMsg, wParam, lParam, plResult, hWndRebar);*/
261 hRet = m_WindowEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, plResult);
262
263 #if 0
264 if (FAILED(hRet))
265 {
266 if (uMsg == WM_NOTIFY)
267 {
268 const NMHDR *nmh = (const NMHDR *) lParam;
269 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);
270 }
271 else
272 {
273 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);
274 }
275 }
276 #endif
277
278 return hRet;
279 }
280
281 virtual HRESULT STDMETHODCALLTYPE AddContextMenus(
282 IN HMENU hmenu,
283 IN UINT indexMenu,
284 IN UINT idCmdFirst,
285 IN UINT idCmdLast,
286 IN UINT uFlags,
287 OUT IContextMenu **ppcm)
288 {
289 if (m_ContextMenu == NULL)
290 {
291 HRESULT hRet;
292 CComPtr<IShellService> pSs;
293
294 /* Cache the context menu so we don't need to CoCreateInstance all the time... */
295 hRet = CoCreateInstance(CLSID_BandSiteMenu, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellService, &pSs));
296 TRACE("CoCreateInstance(CLSID_BandSiteMenu) for IShellService returned: 0x%x\n", hRet);
297 if (!SUCCEEDED(hRet))
298 return hRet;
299
300 hRet = pSs->SetOwner((IBandSite*)this);
301 if (!SUCCEEDED(hRet))
302 {
303 return hRet;
304 }
305
306 hRet = pSs->QueryInterface(IID_PPV_ARG(IContextMenu, &m_ContextMenu));
307
308 if (!SUCCEEDED(hRet))
309 return hRet;
310 }
311
312 if (ppcm != NULL)
313 {
314 m_ContextMenu->AddRef();
315 *ppcm = m_ContextMenu;
316 }
317
318 /* Add the menu items */
319 return m_ContextMenu->QueryContextMenu(hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
320 }
321
322 virtual HRESULT STDMETHODCALLTYPE Lock(IN BOOL bLock)
323 {
324 BOOL bPrevLocked = Locked;
325 BANDSITEINFO bsi;
326 HRESULT hRet;
327
328 ASSERT(m_BandSite != NULL);
329
330 if (bPrevLocked != bLock)
331 {
332 Locked = bLock;
333
334 bsi.dwMask = BSIM_STYLE;
335 bsi.dwStyle = (Locked ? BSIS_LOCKED | BSIS_NOGRIPPER : BSIS_AUTOGRIPPER);
336
337 hRet = m_BandSite->SetBandSiteInfo(&bsi);
338 if (SUCCEEDED(hRet))
339 {
340 hRet = Update();
341 }
342
343 return hRet;
344 }
345
346 return S_FALSE;
347 }
348
349 /*******************************************************************/
350
351 virtual HRESULT STDMETHODCALLTYPE AddBand(IN IUnknown *punk)
352 {
353 /* Send the DBID_DELAYINIT command to initialize the band to be added */
354 /* FIXME: Should be delayed */
355 IUnknown_Exec(punk, IID_IDeskBand, DBID_DELAYINIT, 0, NULL, NULL);
356
357 return m_BandSite->AddBand(punk);
358 }
359
360 virtual HRESULT STDMETHODCALLTYPE EnumBands(
361 IN UINT uBand,
362 OUT DWORD *pdwBandID)
363 {
364 return m_BandSite->EnumBands(uBand, pdwBandID);
365 }
366
367 virtual HRESULT STDMETHODCALLTYPE QueryBand(
368 IN DWORD dwBandID,
369 OUT IDeskBand **ppstb,
370 OUT DWORD *pdwState,
371 OUT LPWSTR pszName,
372 IN int cchName)
373 {
374 HRESULT hRet;
375 IDeskBand *pstb = NULL;
376
377 hRet = m_BandSite->QueryBand(
378 dwBandID,
379 &pstb,
380 pdwState,
381 pszName,
382 cchName);
383
384 if (SUCCEEDED(hRet))
385 {
386 hRet = IsSameObject(pstb, m_TaskBand);
387 if (hRet == S_OK)
388 {
389 /* Add the BSSF_UNDELETEABLE flag to pdwState because the task bar band shouldn't be deletable */
390 if (pdwState != NULL)
391 *pdwState |= BSSF_UNDELETEABLE;
392 }
393 else if (!SUCCEEDED(hRet))
394 {
395 pstb->Release();
396 pstb = NULL;
397 }
398
399 if (ppstb != NULL)
400 *ppstb = pstb;
401 }
402 else if (ppstb != NULL)
403 *ppstb = NULL;
404
405 return hRet;
406 }
407
408 virtual HRESULT STDMETHODCALLTYPE SetBandState(
409 IN DWORD dwBandID,
410 IN DWORD dwMask,
411 IN DWORD dwState)
412 {
413 return m_BandSite->SetBandState(dwBandID, dwMask, dwState);
414 }
415
416 virtual HRESULT STDMETHODCALLTYPE RemoveBand(
417 IN DWORD dwBandID)
418 {
419 return m_BandSite->RemoveBand(dwBandID);
420 }
421
422 virtual HRESULT STDMETHODCALLTYPE GetBandObject(
423 IN DWORD dwBandID,
424 IN REFIID riid,
425 OUT VOID **ppv)
426 {
427 return m_BandSite->GetBandObject(dwBandID, riid, ppv);
428 }
429
430 virtual HRESULT STDMETHODCALLTYPE SetBandSiteInfo(
431 IN const BANDSITEINFO *pbsinfo)
432 {
433 return m_BandSite->SetBandSiteInfo(pbsinfo);
434 }
435
436 virtual HRESULT STDMETHODCALLTYPE GetBandSiteInfo(
437 IN OUT BANDSITEINFO *pbsinfo)
438 {
439 return m_BandSite->GetBandSiteInfo(pbsinfo);
440 }
441
442 virtual BOOL HasTaskBand()
443 {
444 ASSERT(m_TaskBand != NULL);
445
446 return SUCCEEDED(m_TaskBand->GetRebarBandID(NULL));
447 }
448
449 virtual HRESULT AddTaskBand()
450 {
451 #if 0
452 /* FIXME: This is the code for the simple taskbar */
453 IObjectWithSite *pOws;
454 HRESULT hRet;
455
456 hRet = TaskBand->QueryInterface(
457 &IID_IObjectWithSite,
458 (PVOID*) &pOws);
459 if (SUCCEEDED(hRet))
460 {
461 hRet = pOws->SetSite(
462 (IUnknown *)TaskBand);
463
464 pOws->Release();
465 }
466
467 return hRet;
468 #else
469 if (!HasTaskBand())
470 {
471 return m_BandSite->AddBand(m_TaskBand);
472 }
473
474 return S_OK;
475 #endif
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 (RegCreateKey(hkExplorer,
568 TEXT("Streams"),
569 &hkStreams) == ERROR_SUCCESS)
570 {
571 Stream = SHOpenRegStream(hkStreams,
572 TEXT("Desktop"),
573 TEXT("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 (RegCreateKey(HKEY_LOCAL_MACHINE,
588 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Streams"),
589 &hkStreams) == ERROR_SUCCESS)
590 {
591 Stream = SHOpenRegStream(hkStreams,
592 TEXT("Desktop"),
593 TEXT("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 OUT ITrayWindow *tray, OUT HWND *phWndRebar, OUT HWND *phwndTaskSwitch)
640 {
641 CComPtr<IDeskBarClient> pDbc;
642 CComPtr<IDeskBand> pDb;
643 CComPtr<IOleWindow> pOw;
644 HRESULT hRet;
645
646 *phWndRebar = NULL;
647 *phwndTaskSwitch = NULL;
648
649 m_Tray = tray;
650
651 /* Create a RebarBandSite provided by the shell */
652 hRet = CoCreateInstance(CLSID_RebarBandSite,
653 static_cast<IBandSite*>(this),
654 CLSCTX_INPROC_SERVER,
655 IID_PPV_ARG(IUnknown, &m_Inner));
656 if (!SUCCEEDED(hRet))
657 {
658 return hRet;
659 }
660
661 hRet = m_Inner->QueryInterface(IID_PPV_ARG(IBandSite, &m_BandSite));
662 if (!SUCCEEDED(hRet))
663 {
664 return hRet;
665 }
666
667 hRet = m_Inner->QueryInterface(IID_PPV_ARG(IWinEventHandler, &m_WindowEventHandler));
668 if (!SUCCEEDED(hRet))
669 {
670 return hRet;
671 }
672
673 m_TaskBand = CreateTaskBand(m_Tray);
674 if (m_TaskBand != NULL)
675 {
676 /* Add the task band to the site */
677 hRet = m_BandSite->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDbc));
678 if (SUCCEEDED(hRet))
679 {
680 hRet = m_TaskBand->QueryInterface(IID_PPV_ARG(IOleWindow, &pOw));
681 if (SUCCEEDED(hRet))
682 {
683 /* We cause IDeskBarClient to create the rebar control by passing the new
684 task band to it. The band reports the tray window handle as window handle
685 so that IDeskBarClient knows the parent window of the Rebar control that
686 it wants to create. */
687 hRet = pDbc->SetDeskBarSite(pOw);
688
689 if (SUCCEEDED(hRet))
690 {
691 /* The Rebar control is now created, we can query the window handle */
692 hRet = pDbc->GetWindow(&m_Rebar);
693
694 if (SUCCEEDED(hRet))
695 {
696 /* We need to manually remove the RBS_BANDBORDERS style! */
697 SetWindowStyle(m_Rebar, RBS_BANDBORDERS, 0);
698 }
699 }
700 }
701
702 if (SUCCEEDED(hRet))
703 {
704 DWORD dwMode = 0;
705
706 /* Set the Desk Bar mode to the current one */
707
708 /* FIXME: We need to set the mode (and update) whenever the user docks
709 the tray window to another monitor edge! */
710
711 if (!m_Tray->IsHorizontal())
712 dwMode = DBIF_VIEWMODE_VERTICAL;
713
714 hRet = pDbc->SetModeDBC(dwMode);
715 }
716
717 pDbc->Release();
718 }
719
720 /* Load the saved state of the task band site */
721 /* FIXME: We should delay loading shell extensions, also see DBID_DELAYINIT */
722 Load();
723
724 /* Add the task bar band if it hasn't been added already */
725 hRet = AddTaskBand();
726 if (SUCCEEDED(hRet))
727 {
728 hRet = m_TaskBand->QueryInterface(IID_PPV_ARG(IDeskBand, &pDb));
729 if (SUCCEEDED(hRet))
730 {
731 hRet = pDb->GetWindow(phwndTaskSwitch);
732 if (!SUCCEEDED(hRet))
733 *phwndTaskSwitch = NULL;
734 }
735 }
736
737 /* Should we send this after showing it? */
738 Update();
739
740 /* FIXME: When should we send this? Does anyone care anyway? */
741 FinishInit();
742
743 /* Activate the band site */
744 Show(
745 TRUE);
746 }
747
748 *phWndRebar = m_Rebar;
749
750 return S_OK;
751 }
752 };
753 /*******************************************************************/
754
755 ITrayBandSite *
756 CreateTrayBandSite(IN OUT ITrayWindow *Tray,
757 OUT HWND *phWndRebar,
758 OUT HWND *phWndTaskSwitch)
759 {
760 HRESULT hr;
761
762 CTrayBandSite * tb = new CTrayBandSite();
763
764 if (!tb)
765 return NULL;
766
767 tb->AddRef();
768
769 hr = tb->_Init(Tray, phWndRebar, phWndTaskSwitch);
770 if (FAILED_UNEXPECTEDLY(hr))
771 tb->Release();
772
773 return tb;
774 }