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