#include "priv.h" #include "sccls.h" #include "resource.h" #include "dhuihand.h" #include #include "mstimeid.h" #include #include "mediahlpr.h" #include "mediaband.h" #include "apithk.h" #include "mbBehave.h" #define SUPERCLASS CToolBand #define MIN_WINDOW_WIDTH 145 #define MIN_WINDOW_HEIGHT 60 #define MIN_POPOUT_HEIGHT 300 #define MIN_POPOUT_WIDTH 300 #define MIN_VOLUME_WIDTH 50 #define MIN_VOLUME_HEIGHT 16 #define MIN_HORZ_SPACING 10 #define SEEK_PART_WIDTH 18 #define SEEK_PART_HEIGHT 5 #define SEEK_HEIGHT 16 #define VOLUME_GRIPPER_LENGTH 6 #define COLOR_BKGND16 RGB(192, 192, 192) #define COLOR_BKGNDMIDDLE RGB(99, 129, 193) #define VOLUME_BITMAP_WIDTH 42 #define VIDEO_MIN_HEIGHT 60 #define VIEW_MARGIN_BOTTOM 7 #define VIEW_MARGIN_LEFT 6 #define VIEW_MARGIN_INFO_LEFT 5 #define VIEW_MARGIN_RIGHT 10 #define VIEW_MARGIN_TOP 5 #define VIEW_MARGIN_TOP_VIDEO 6 #define VIEW_MARGIN_BOTTOM 7 #define VIEW_CONTROLS_HEIGHT 33 #define VIEW_CONTROLS_MARGIN 2 #define SCALEX(x) (_fHighDPI ? ((INT)(((float)(x))*_scaleX)) : (x)) #define SCALEY(x) (_fHighDPI ? ((INT)(((float)(x))*_scaleY)) : (x)) #define WZ_SMIE_MEDIA_MIME REG_MEDIA_STR TEXT("\\MimeTypes") #define REG_VALUE_MRU_INTERNET REG_MEDIA_STR TEXT("\\Internet") #define REG_VALUE_PATH TEXT("MusicPath") // // ISSUE: dilipk: these are localizable strings and need to be moved eventually !!! // #define WZ_WINDOWSMEDIA L"http://www.windowsmedia.com" #define WZ_ASX_MIMETYPE L"video/x-ms-asx" static const TCHAR c_szMediaBandProp[] = TEXT("CMediaBand_This"); static const TCHAR c_szMediaBarClassName[] = TEXT("MediaPane"); static const TCHAR c_szMediaBarPopupClassName[] = TEXT("MediaPopupPane"); static const TCHAR c_szMediaBarLayoutClassName[] = TEXT("MediaLayoutPane"); // ISSUE: these two should be deleted when reg utilities are completely moved to mediautil.cpp static const UINT MAX_REG_VALUE_LENGTH = 50; // This is the number of ticks (from MSTIME) to skip each time before polling System Time // for the navigation timeout counter #define POLL_INTERVAL 30 // This is the number of milli-seconds after which navigation times out #define TIMEOUT_INTERVAL 90000 static const TCHAR c_szContentUrl[] = TEXT("http://go.microsoft.com/fwlink/?LinkId=511"); static const TCHAR c_szMoreMediaUrl[] = TEXT("http://go.microsoft.com/fwlink/?LinkId=512"); static const TCHAR c_szRadioUrl[] = TEXT("http://go.microsoft.com/fwlink/?LinkId=822"); static const TCHAR c_szOfflineURL[] = TEXT("mbOffline.htm"); static const TCHAR c_szLoadingURL[] = TEXT("mbLoading.htm"); static const TCHAR c_sz404URL[] = TEXT("mb404.htm"); extern HBITMAP CreateMirroredBitmap( HBITMAP hbmOrig); // // ISSUE: this is a temporary guid for the content pane sync feature. // static const IID SID_SMediaBarSync = { 0x2efc8085, 0x066b, 0x4823, { 0x9d, 0xb4, 0xd1, 0xe7, 0x69, 0x16, 0xda, 0xa0 } }; static const GUID SID_STimeContent = { 0x1ae98e18, 0xc527, 0x4f78, {0xb2, 0xa2, 0x6a, 0x81, 0x7f, 0x9c, 0xd4, 0xf8}}; // ISSUE where could be #include this GUID from????? static const GUID CLSID_JITWMP8 = { 0x6BF52A52, 0x394A, 0x11d3, 0xb1, 0x53, 0x00, 0xc0, 0x4f, 0x79, 0xfa, 0xa6 }; CMediaBand::CMediaBand() : _fPlayButton(TRUE), _fPlayEnabled(TRUE), _iCurTrack(-1), _lTickCount(-1), _iElement(-1), _dblVol(-1.0), _fHiColour(TRUE), _fUserPaused(FALSE), _iOptionsWidth(0), _hbmpBackground(NULL), _hwndContent(NULL), _dwcpCookie(0), _fContentInFocus(FALSE), _hkeyWMP(NULL), _fShow(FALSE), _fAttached(FALSE) { _sizeLayout.cx = MIN_WINDOW_WIDTH; _sizeLayout.cy = MIN_WINDOW_HEIGHT; _sizeVideo.cx = 0 ; _sizeVideo.cy = 0 ; _fCanFocus = TRUE; _scaleX = _scaleY = 1.0; // HighDPI support requires nice comctl32 6.0 functionality. if (IsOS(OS_WHISTLERORGREATER)) { HDC hdcScreen = GetDC(NULL); if (hdcScreen) { _scaleX = (GetDeviceCaps(hdcScreen, LOGPIXELSX) / 96.0f); _scaleY = (GetDeviceCaps(hdcScreen, LOGPIXELSY) / 96.0f); ReleaseDC(NULL, hdcScreen); } } _fHighDPI = (_scaleX!=1.0) || (_scaleY!=1.0); } CMediaBand::~CMediaBand() { DestroyPlayer(); if (_spBrowser) { _ConnectToCP(FALSE); _spBrowser.Release(); _poipao.Release(); } DESTROY_OBJ_WITH_HANDLE(_hwndContent, DestroyWindow); DESTROY_OBJ_WITH_HANDLE(_hwndPopup, DestroyWindow); DESTROY_OBJ_WITH_HANDLE(_hwndLayout, DestroyWindow); DESTROY_OBJ_WITH_HANDLE(_hPlayListMenu, DestroyMenu); DESTROY_OBJ_WITH_HANDLE(_himlSeekBack, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_himlSeekFill, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_himlGripper, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_himlVolumeBack, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_himlVolumeFill, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_hbmpBackground, DeleteObject); // need to check IsWindow because this window can also be destroyed by CMediaBarPlayer if (_hwndVideo && ::IsWindow(_hwndVideo)) DestroyWindow(_hwndVideo); if (_szToolTipUrl) { delete [] _szToolTipUrl; } if (_pszStatus) { delete [] _pszStatus; } for (int i=0; i < ARRAYSIZE(_pmw); i++) { if (_pmw[i]) { delete _pmw[i]; } } if (_hkeyWMP) RegCloseKey(_hkeyWMP); } // helper to get up to service provider and to do register/unregister // two forms: // pService != NULL, register, pdwCookie is [out] returns cookie // pService == NULL, unregister, *pdwCookie is [in] de-registers the service STDMETHODIMP CMediaBand::ProfferService(IUnknown *punkSite, REFGUID sidWhat, IServiceProvider *pService, DWORD *pdwCookie) { IProfferService *pps; HRESULT hr = IUnknown_QueryService(punkSite, SID_SProfferService, IID_PPV_ARG(IProfferService, &pps)); if (SUCCEEDED(hr)) { if (pService) hr = pps->ProfferService(sidWhat, pService, pdwCookie); else { hr = pps->RevokeService(*pdwCookie); *pdwCookie = 0; } pps->Release(); } return hr; } HRESULT CMediaBand::SetSite(IUnknown *punkSite) { // Make sure we proffer the service only once // This is important since we get created multiple times, CComPtr spUnk; // Check if we need to revoke our service, or if our service was already proffered by // another instance of CMediaBar if ((!punkSite && _dwCookieServiceMediaBar) || (punkSite && FAILED(IUnknown_QueryService(punkSite, SID_SMediaBar, IID_PPV_ARG(IUnknown, &spUnk))))) { // Proffer or Revoke BrandBand service as appropriate ProfferService(punkSite ? punkSite : _punkSite, SID_SMediaBar, punkSite ? SAFECAST(this, IServiceProvider *) : NULL, &_dwCookieServiceMediaBar); // Failure here does not require special handling } return SUPERCLASS::SetSite(punkSite); } HRESULT CMediaBand::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CMediaBand, IMediaBar), QITABENT(CMediaBand, IWinEventHandler), QITABENT(CMediaBand, IObjectWithSite), QITABENT(CMediaBand, INamespaceWalkCB), QITABENTMULTI(CMediaBand, IDispatch, DWebBrowserEvents2), QITABENTMULTI2(CMediaBand, DIID_DWebBrowserEvents2, DWebBrowserEvents2), QITABENT(CMediaBand, IElementBehaviorFactory), QITABENT(CMediaBand, IBrowserBand), QITABENT(CMediaBand, IBandNavigate), QITABENT(CMediaBand, IMediaHost), { 0 }, }; HRESULT hr = QISearch(this, qit, riid, ppv); if (FAILED(hr)) { hr = SUPERCLASS::QueryInterface(riid, ppv); } return hr; } // *** IWinEventHandler *** HRESULT CMediaBand::IsWindowOwner(HWND hwnd) { for (int i=0; i < ARRAYSIZE(_pmw); i++) { if (_pmw[i] && (hwnd==_pmw[i]->_hwnd)) { return S_OK; } } return S_FALSE; } // *** IWinEventHandler *** HRESULT CMediaBand::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres) { CMediaBand* pmb = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); switch (uMsg) { case WM_COMMAND: { HWND hwndControl = GET_WM_COMMAND_HWND(wParam, lParam); UINT idCmd = GET_WM_COMMAND_ID(wParam, lParam); if (HIWORD(wParam) == BN_CLICKED && hwndControl) { RECT rc; VARIANTARG var; var.vt = VT_I4; GetWindowRect(hwndControl, &rc); MapWindowPoints(hwndControl, HWND_DESKTOP, (LPPOINT)&rc, 2); var.lVal = MAKELONG(rc.left, rc.bottom); return Exec(&CLSID_MediaBand, idCmd, 0, &var, NULL); } } break; } return S_FALSE; } void CMediaBand::_ClearFolderItems() { if (_ppidls) { FreeIDListArray(_ppidls, _cidls); _ppidls = NULL; } _cidls = 0; } // INamespaceWalkCB methods HRESULT CMediaBand::FoundItem(IShellFolder *psf, LPCITEMIDLIST pidl) { if (NULL == _hkeyWMP) { RegOpenKey(HKEY_CLASSES_ROOT, TEXT("Applications\\mplayer2.exe\\SupportedTypes"), &_hkeyWMP); } HRESULT hr = S_FALSE; // default to no if (_hkeyWMP) { TCHAR szName[MAX_PATH]; if (SUCCEEDED(DisplayNameOf(psf, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, szName, ARRAYSIZE(szName)))) { if (ERROR_SUCCESS == RegQueryValueEx(_hkeyWMP, PathFindExtension(szName), NULL, NULL, NULL, NULL)) { hr = S_OK; } } } return hr; } STDMETHODIMP CMediaBand::InitializeProgressDialog(LPWSTR *ppszTitle, LPWSTR *ppszCancel) { TCHAR szText[200]; MLLoadString(IDS_MEDIABANDSEARCH, szText, ARRAYSIZE(szText)); SHStrDup(szText, ppszTitle); *ppszCancel = NULL; return S_OK; } HRESULT CMediaBand::_GetMusicFromFolder() { _ClearFolderItems(); INamespaceWalk *pnsw; HRESULT hr = CoCreateInstance(CLSID_NamespaceWalker, NULL, CLSCTX_INPROC, IID_PPV_ARG(INamespaceWalk, &pnsw)); if (SUCCEEDED(hr)) { hr = pnsw->Walk(_punkSite, NSWF_ONE_IMPLIES_ALL | NSWF_NONE_IMPLIES_ALL | NSWF_SHOW_PROGRESS, 10, this); if (SUCCEEDED(hr)) { hr = pnsw->GetIDArrayResult(&_cidls, &_ppidls); } pnsw->Release(); } return hr; } // *** IOleCommandTarget methods *** HRESULT CMediaBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { HRESULT hr = S_OK; if (pguidCmdGroup) { if (IsEqualGUID(CLSID_MediaBand, *pguidCmdGroup)) { switch (nCmdID) { case FCIDM_MEDIABAND_POPOUT: { DockMediaPlayer(); } break; case FCIDM_MEDIABAND_PLAY: if (!_pMediaPlayer || _pMediaPlayer->isStopped()) { _CleanupStopTimer(); hr = _GetMusicFromFolder(); if (S_OK == hr) { _strLastUrl.Empty(); // would be nicer to replay same local file if navigated away.... PlayLocalTrack(0); } else if (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr) { // if we already played a media in this session, replay it if (_strLastUrl.Length() > 0) { if (_fLastUrlIsAutoPlay) { // repeat playing last auto-play CComVariant vtURL = _strLastUrl; CComVariant vtMime = _strLastMime; Exec(&CGID_MediaBar, MBID_PLAY, 0, &vtMime, &vtURL); } else { // replay media thru content pane and media bar behavior NavigateContentPane(_strLastUrl); } } else { NavigateMoreMedia(); } } } else { _TogglePause(); TogglePlayPause(); } break; case FCIDM_MEDIABAND_PREVIOUS: if (EnsurePlayer()) { LONG_PTR lCurTrack = _pMediaPlayer->GetPlayListItemIndex(); LONG_PTR lItemCount = _pMediaPlayer->GetPlayListItemCount(); if (lCurTrack > 0) { _pMediaPlayer->Prev(); } else if (_iCurTrack >= 0) { int i = _iCurTrack; _iCurTrack = -1; // don't auto-step to next on finished event _pMediaPlayer->Stop(); // generates MEDIA_TRACK_FINISHED PlayLocalTrack((i - 1 >= 0) ? i - 1 : 0); } UpdateBackForwardControls(); TogglePlayPause(); } break; case FCIDM_MEDIABAND_NEXT: if (EnsurePlayer()) { LONG_PTR lCurTrack = _pMediaPlayer->GetPlayListItemIndex(); LONG_PTR lItemCount = _pMediaPlayer->GetPlayListItemCount(); if ((lCurTrack >= 0) && (lCurTrack < lItemCount - 1)) { _pMediaPlayer->Next(); } else if (_iCurTrack >= 0) { int i = _iCurTrack; _iCurTrack = -1; // don't auto-step to next on finished event _pMediaPlayer->Stop(); // generates MEDIA_TRACK_FINISHED PlayLocalTrack(i + 1); } UpdateBackForwardControls(); TogglePlayPause(); } break; case FCIDM_MEDIABAND_STOP: // when player is attached thru mediaBar behavior to script in media content pane, // we want to give the user a chance to get rid of the script and return to the default media content // the first click simply stops the player, clicking again within N secs will also navigate // the content pane to the default URL if (_idStopTimer == 0) { if (_IsProxyRunning()) { _idStopTimer = SetTimer(_hwnd, 747, 10000, NULL); } ResetPlayer(); _OnUserOverrideDisableUI(); } else { // clicked again, navigate media content to default URL _CleanupStopTimer(); _NavigateContentToDefaultURL(); } break; case FCIDM_MEDIABAND_MUTE: ToggleMute(); break; } } else if (IsEqualGUID(CGID_MediaBar, *pguidCmdGroup)) { switch (nCmdID) { case MBID_PLAY: if (pvarargIn && pvarargOut) { _CleanupStopTimer(); if (_IsProxyRunning()) { // user clicked on a media link in the main content pane, unfreeze controls! _OnUserOverrideDisableUI(); _DetachProxies(); _NavigateContentToDefaultURL(); } if (V_VT(pvarargOut) == VT_BSTR) { _strLastUrl = V_BSTR(pvarargOut); } if (V_VT(pvarargIn) == VT_BSTR) { _strLastMime = V_BSTR(pvarargIn); } _fLastUrlIsAutoPlay = TRUE; // ISSUE: fix this to use the right CmdId & CmdIdGroup, not just zero, to prevent collisions. // this is an auto-play command _HandleAutoPlay(pvarargIn, pvarargOut); hr = S_OK; } break; case MBID_POPOUT: if (pvarargOut) { V_VT(pvarargOut) = VT_BOOL; V_BOOL(pvarargOut) = _hwndPopup && IsWindowVisible(_hwndPopup); hr = S_OK; } break; default: ASSERT(FALSE); break; } } else { hr = SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } } else { hr = SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } return hr; } void CMediaBand::_HandleAutoPlay(VARIANTARG *pvarargMime, VARIANTARG *pvarargUrl) { // check the mime type argument if ( (!pvarargMime) || (VT_BSTR != V_VT(pvarargMime)) || (!V_BSTR(pvarargMime)) || (L'' == (*V_BSTR(pvarargMime)))) { goto done; } // check the Url argument if ( (!pvarargUrl) || ( VT_BSTR != V_VT(pvarargUrl)) || (!V_BSTR(pvarargUrl)) || (L'' == (*V_BSTR(pvarargUrl)))) { goto done; } if (EnsurePlayer()) { // reset this to -1 to indicate we are not playing a mymusic track _iCurTrack = -1; #ifdef _USE_MEDIA_MRU // ISSUE: temp fix for radio protocol. If this is an ASX mimetype, we know it is radio if (!SHRestricted(REST_NORECENTDOCSHISTORY)) { CMediaMRU mmru; mmru.Load(REG_VALUE_MRU_INTERNET); mmru.Add(V_BSTR(pvarargUrl)); } #endif // _USE_MEDIA_MRU if (0 == StrCmpNIW(V_BSTR(pvarargMime), WZ_ASX_MIMETYPE, wcslen(WZ_ASX_MIMETYPE))) { _PutUrl(V_BSTR(pvarargUrl), V_BSTR(pvarargMime)); } else { _PutUrl(V_BSTR(pvarargUrl), NULL); } TogglePlayPause(); // clear the url to indicate we are handling this url ::VariantClear(pvarargUrl); } else { ASSERT(FALSE); } done: ; } VOID CMediaBand::_BeginTimeOutCounter(BOOL fClear /* = TRUE */) { _dwStartTime = GetPerfTime(); _lTickCount = 0; if (TRUE == fClear) { _dblLastBufProgress = 0; _dblLastPlayProgress = 0; } } VOID CMediaBand::_EndTimeOutCounter() { _lTickCount = -1; } VOID CMediaBand::_UpdateTimeOutCounter(double dblCurrBufProgress, double dblCurrPlayProgress) { BOOL fTimeOut = FALSE; // bail if the counter has not been started if (_lTickCount < 0) return; // Order of checking is important here. // If play progress is increasing then restart the counter if (dblCurrPlayProgress > _dblLastPlayProgress) { _BeginTimeOutCounter(FALSE); _dblLastPlayProgress = dblCurrPlayProgress; } // if buffering progress is increasing then restart the counter else if (dblCurrBufProgress > _dblLastBufProgress) { _BeginTimeOutCounter(FALSE); _dblLastBufProgress = dblCurrBufProgress; } else { // both play and buffering progress are stalled, so update the timeout counter // We poll the system time every POLL_INTERVAL ticks since we tick at a very high rate // (a tick is each time this function is called) if ((1 + _lTickCount) == POLL_INTERVAL) { DWORD dwCurrentTime = GetPerfTime(); DWORD dwElapsedTime = (dwCurrentTime - _dwStartTime) + (dwCurrentTime < _dwStartTime ? 0xffffffff : 0); // if timer wraps around 2^32 milliseconds if (dwElapsedTime >= TIMEOUT_INTERVAL) { fTimeOut = TRUE; } } if (fTimeOut) { _OnNavigationTimeOut(); } else { // update the poll interval counter and mod it by POLL_INTERVAL _lTickCount = (1 + _lTickCount) - (static_cast(_lTickCount / POLL_INTERVAL) * POLL_INTERVAL); } } } VOID CMediaBand::_OnNavigationTimeOut() { _EndTimeOutCounter(); // stop the player and show the timeout message if (EnsurePlayer()) { if (VARIANT_FALSE == _pMediaPlayer->isStopped()) { _pMediaPlayer->Stop(); TogglePlayPause(); // Show timeout error message TCHAR szText[200]; szText[0] = TEXT('\0'); MLLoadString(IDS_MEDIABAND_NAVTIMEOUT, szText, ARRAYSIZE(szText)); SetStatusText(szText); } } } STDMETHODIMP CMediaBand::_PutUrl(LPWSTR pstrUrl, LPWSTR pstrMime) { HRESULT hr = E_FAIL; if (EnsurePlayer()) { TCHAR szText[200]; szText[0] = TEXT('\0'); SetStatusText(_szConnecting); hr = _pMediaPlayer->put_type(pstrMime); if (SUCCEEDED(hr)) { hr = _pMediaPlayer->put_url(pstrUrl); if (SUCCEEDED(hr)) { // start the timeout counter if (_dblVol!=-1) { _pMediaPlayer->put_volume(_dblVol); } _pMediaPlayer->put_mute(_fMuted); _BeginTimeOutCounter(); UpdateBackForwardControls(); SetPlayPause(FALSE); SetPlayerControl(FCIDM_MEDIABAND_STOP, TRUE); // make sure we undavise from soon-to-be obsolete player object _AttachPlayerToProxies(FALSE); } } } return hr; } // *** IInputObject methods *** HRESULT CMediaBand::TranslateAcceleratorIO(LPMSG pMsg) { ASSERT(pMsg); TraceMsg(TF_ACCESSIBILITY, "CMediaBand::TranslateAcceleratorIO (hwnd=0x%08X) key=%d", _hwnd, pMsg->wParam); BOOL fHasFocus = ( (_iElement>=0) || (HasFocusIO() == S_OK) || _fContentInFocus); if (fHasFocus && IsVK_CtlTABCycler(pMsg)) { // Bail on ctl-tab/F6 if one of our guys already has focus return S_FALSE; } // if any child in focus, let them have a shot at it HRESULT hr = S_FALSE; if (fHasFocus) { if (_iElement >=0) { if (_hwndPopup && IsWindowVisible(_hwndPopup) && (pMsg->message==WM_KEYDOWN) && (pMsg->wParam==VK_ESCAPE)) { DockMediaPlayer(); hr = S_OK; } else { hr = _pmw[_iElement]->TranslateAccelerator(pMsg); } } else if (_fContentInFocus && _poipao) { hr = _poipao->TranslateAccelerator(pMsg); } if (hr == S_OK) { return S_OK; // handled!! } } hr = S_FALSE; // try shifting focus to next element if (IsVK_TABCycler(pMsg)) { BOOL fReverse = (GetKeyState(VK_SHIFT) < 0); if (fReverse) { // content pane is last tab target, move to last control widget with this backward tab if (_fContentInFocus) { _ContentActivateIO(FALSE, NULL); if (!(_hwndPopup && IsWindowVisible(_hwndPopup))) { _iElement = ARRAYSIZE(_pmw)-1; } else { return S_FALSE; } } else do { _iElement--; if (_iElement<0) { if (_fPopoutHasFocus) { _iElement = ARRAYSIZE(_pmw)-1; } break; } } while (!ISVALIDWIDGET(_pmw[_iElement]) || (!_pmw[_iElement]->IsEnabled())); } else { // content pane is last tab target, move away from mediabar with this forward tab if (_fContentInFocus) { _ContentActivateIO(FALSE, NULL); return S_FALSE; } // try next control widget if (!(_hwndPopup && IsWindowVisible(_hwndPopup)) || _fPopoutHasFocus) { if (_iElement<0) { _iElement = 0; } else do { _iElement++; if (_iElement>=ARRAYSIZE(_pmw)) { _iElement = _fPopoutHasFocus ? 0 : -1; break; } } while (!ISVALIDWIDGET(_pmw[_iElement]) || (!_pmw[_iElement]->IsEnabled())); } // none of the control widgets claimed focus, try content pane if (_iElement<0) { hr = _ContentActivateIO(TRUE, pMsg); if (hr == S_OK) { return S_OK; // handled!! } } } if (_iElement<0) { return S_FALSE; } ASSERT(ISVALIDWIDGET(_pmw[_iElement])); ::SetFocus(_pmw[_iElement]->_hwnd); return S_OK; } return S_FALSE; // unhandled non-tab } //------------------------------------------------------------------------ HRESULT CMediaBand::UIActivateIO(BOOL fActivate, LPMSG pMsg) { TraceMsg(TF_ACCESSIBILITY, "CMediaBand::UIActivateIO (hwnd=0x%08X) fActivate=%d", _hwnd, fActivate); HRESULT hr = S_OK; // activation: if (fActivate) { if (!(_hwndPopup && IsWindowVisible(_hwndPopup)) || _fPopoutHasFocus) { if (_iElement==-1) { _ContentActivateIO(FALSE, NULL); _iElement = 0; } if (_pmw[_iElement] && _pmw[_iElement]->_hwnd) { ::SetFocus(_pmw[_iElement]->_hwnd); } } else { _iElement = -1; _ContentActivateIO(TRUE, pMsg); } IUnknown_OnFocusChangeIS(_punkSite, SAFECAST(this, IInputObject*), TRUE); } else { _ContentActivateIO(FALSE, NULL); _iElement = -1; if (_hwndPopup && IsWindowVisible(_hwndPopup)) { IUnknown_OnFocusChangeIS(_punkSite, SAFECAST(this, IInputObject*), FALSE); } } return hr; } //------------------------------------------------------------------------ HRESULT CMediaBand::HasFocusIO() { HRESULT hr = SHIsChildOrSelf((_hwndPopup && IsWindowVisible(_hwndPopup)) ? _hwndPopup : _hwnd, ::GetFocus()); if (hr==S_FALSE) { // Focus might be in the content pane, which won't be a child if the popout is out hr = SHIsChildOrSelf(_hwndContent, ::GetFocus()); } return hr; } HRESULT CMediaBand::_ContentActivateIO(BOOL fActivate, PMSG pMsg) { ASSERT(_hwndContent); ASSERT(_poipao); if (_fContentInFocus == fActivate) { return S_OK; } _fContentInFocus = fActivate; if (fActivate) { _iElement = -1; } int iVerb = fActivate ? OLEIVERB_UIACTIVATE : OLEIVERB_INPLACEACTIVATE; HRESULT hr = S_OK; hr = OCHost_DoVerb(_hwndContent, iVerb, pMsg); // OCHost UIActivate is different than IInputObject::UIActivateIO. It // doesn't do anything with the lpMsg parameter. So, we need to pass // it to them via TranslateAccelerator. Since the only case we care // about is when they're getting tabbed into (we want them to highlight // the first/last link), just do this in the case of a tab. However, // don't give it to them if it's a ctl-tab. The rule is that you shouldn't // handle ctl-tab when UI-active (ctl-tab switches between contexts), and // since Trident is always UI-active (for perf?), they'll always reject // ctl-tab. // suppress sending any tabs if (pMsg && _poipao && IsVK_TABCycler(pMsg) && !IsVK_CtlTABCycler(pMsg)) { hr = _poipao->TranslateAccelerator(pMsg); // ignore if translate of tab fails when activating! if (FAILED(hr) && fActivate) { hr = S_OK; } } return hr; } LRESULT CMediaBand::_OnNotify(LPNMHDR pnm) { switch (pnm->code) { case OCN_ONUIACTIVATE: // UIActivate ASSERT(SHIsSameObject(((LPOCNONUIACTIVATEMSG)pnm)->punk, _poipao)); _fContentInFocus = TRUE; _iElement = -1; IUnknown_OnFocusChangeIS(_punkSite, SAFECAST(this, IInputObject*), TRUE); return OCNONUIACTIVATE_HANDLED; case OCN_ONSETSTATUSTEXT: { HRESULT hr = E_FAIL; IShellBrowser *psb; hr = QueryService(SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser, &psb)); if (SUCCEEDED(hr)) { hr = psb->SetStatusTextSB(((LPOCNONSETSTATUSTEXTMSG)pnm)->pwszStatusText); psb->Release(); } } break; default: break; } ASSERT(OCNONUIACTIVATE_HANDLED != 0); return 0; } // *** IDeskBand methods *** HRESULT CMediaBand::GetBandInfo(DWORD dwBandID, DWORD fViewMode, DESKBANDINFO* pdbi) { _dwBandID = dwBandID; pdbi->dwModeFlags = DBIMF_FIXEDBMP | DBIMF_VARIABLEHEIGHT; if (pdbi->dwMask & DBIM_MINSIZE) { pdbi->ptMinSize.x = 16; pdbi->ptMinSize.y = 16; } if (pdbi->dwMask & DBIM_MAXSIZE) { pdbi->ptMaxSize.x = 32000; // random pdbi->ptMaxSize.y = 32000; // random } if (pdbi->dwMask & DBIM_ACTUAL) { pdbi->ptActual.x = -1; pdbi->ptActual.y = -1; } if (pdbi->dwMask & DBIM_INTEGRAL) { pdbi->ptIntegral.y = 1; } MLLoadStringW(IDS_MEDIABANDTEXT, pdbi->wszTitle, ARRAYSIZE(pdbi->wszTitle)); return S_OK; } /*** CMediaBand::IPersistStream::**/ HRESULT CMediaBand::GetClassID(CLSID *pClassID) { *pClassID = CLSID_MediaBand; return S_OK; } // *** IPersistStream methods *** HRESULT CMediaBand::Load(IStream *pstm) { return S_OK; } // *** IPersistStream methods *** HRESULT CMediaBand::Save(IStream *pstm, BOOL fClearDirty) { return S_OK; } // *** IOleWindow methods *** HRESULT CMediaBand::GetWindow(HWND *phwnd) { if (!_hwnd) { CreateParentPane(); } if (!_hwndLayout) { CreateLayoutPane(); } if (!_hwndContent) { InitContentPane(); } if (phwnd) { *phwnd = _hwnd ; return S_OK; } return SUPERCLASS::GetWindow(phwnd); } // *** IDockingWindow methods *** HRESULT CMediaBand::ShowDW(BOOL fShow) { if (!_hwnd) return S_FALSE; // The window needs to be created first. _fVideoAdjust = FALSE; if (fShow) { _InitializeMediaUI(); // FEATURE/010228/davidjen uncomment this to suppress MediaBar's title bar #ifdef _SUPPRESS_MB_TITLEBAR // hide caption/titlebar CComQIPtr pbs = _punkSite; if (pbs) { BANDSITEINFO bsi; bsi.dwMask = BSIM_STYLE; HRESULT hr = pbs->GetBandSiteInfo(&bsi); if (SUCCEEDED(hr)) { // suppress caption bsi.dwStyle |= BSIS_NOCAPTION; hr = pbs->SetBandSiteInfo(&bsi); } } #endif // _SUPPRESS_MB_TITLEBAR if (!(_hwndPopup && IsWindowVisible(_hwndPopup))) { RECT rcParent, rc; GetClientRect(_hwnd, &rcParent); GetClientRect(_hwndLayout, &rc); if (RECTWIDTH(rcParent) > 0 || RECTHEIGHT(rcParent) > 0) { _ResizeChildWindows(_hwndLayout, RECTWIDTH(rc), RECTHEIGHT(rc), TRUE); SetWindowPos(_hwnd, NULL, 0, 0,RECTWIDTH(rcParent), RECTHEIGHT(rcParent), SWP_SHOWWINDOW | SWP_NOACTIVATE); RedrawWindow(_hwnd, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN); } } } else { _ShowAllWindows(fShow); } if (fShow != _fShow) { _fShow = fShow; _FireEventToProxies(_fShow ? OnShow : OnHide); } return CToolBand::ShowDW(fShow); } HRESULT CMediaBand::CloseDW(DWORD dwReserved) { if (!_hwnd) return S_FALSE; // The window needs to be created first. WTSUnRegisterSessionNotification(_hwnd); DestroyPlayer(); if (_spBrowser) { _ConnectToCP(FALSE); _spBrowser.Release(); _poipao.Release(); } if (_hwndLayout && IsWindow(_hwndLayout)) { DestroyWindow(_hwndLayout); _hwndLayout = NULL; } if (_hwndPopup && IsWindow(_hwndPopup)) { DestroyWindow(_hwndPopup); _hwndPopup = NULL; } SUPERCLASS::CloseDW(dwReserved); return S_OK; } //-------------- Interface IElementBehaviorFactory //------------------------------------------------------------------------ STDMETHODIMP CMediaBand::FindBehavior(BSTR bstrBehavior, BSTR bstrBehaviorUrl, IElementBehaviorSite* pSite, IElementBehavior** ppBehavior) { if (ppBehavior == NULL) { return E_POINTER; } *ppBehavior = NULL; // check namespace and URL if (StrCmpIW(bstrBehavior, TEXT("mediaBar")) != 0) { return E_NOTIMPL; // don't know this behavior!! } HRESULT hr = S_OK; // create new behavior instance for this HTML pane IContentProxy * pProxy = NULL; pProxy = CMediaBehavior_CreateInstance(this); if (pProxy) { hr = pProxy->QueryInterface(IID_IElementBehavior, (void**)ppBehavior); if (FAILED(hr)) { // make sure we get rid our reference removeProxy(pProxy); } } else { hr = E_OUTOFMEMORY; } return hr; } // IMediaHost //------------------------------------------------------------------------ STDMETHODIMP CMediaBand::getMediaPlayer(IUnknown **ppPlayer) { if (ppPlayer == NULL) return E_POINTER; *ppPlayer = NULL; if (_pMediaPlayer) { ITIMEMediaElement *pElem = NULL; if (SUCCEEDED(_pMediaPlayer->get_mediaElement(&pElem))) { *ppPlayer = pElem; // no AddRef, get_mediaElement already did ref counting!! } } return *ppPlayer ? S_OK : S_FALSE; } //------------------------------------------------------------------------ STDMETHODIMP CMediaBand::playURL(BSTR bstrURL, BSTR bstrMIME) { HRESULT hr = _EnsureWMPInstalled(); if (FAILED(hr)) { return hr; } CComVariant varMime = bstrMIME; CComVariant varUrl = bstrURL; _strLastUrl = _strCurrentContentUrl; _strLastMime.Empty(); _fLastUrlIsAutoPlay = FALSE; _HandleAutoPlay(&varMime, &varUrl); return S_OK; } //------------------------------------------------------------------------ STDMETHODIMP CMediaBand::addProxy(IUnknown *punkProxy) { HRESULT hr = E_POINTER; if (punkProxy) { // add to our array of proxies if (_apContentProxies == NULL) { _apContentProxies.Create(2); } if (_apContentProxies == NULL) { return E_OUTOFMEMORY; } // want to be sure proxy knows our protocol, also does add ref IContentProxy *pProxy = NULL; hr = punkProxy->QueryInterface(IID_PPV_ARG(IContentProxy, &pProxy)); if (SUCCEEDED(hr)) { _apContentProxies.AppendPtr(pProxy); } } return hr; } //------------------------------------------------------------------------ STDMETHODIMP CMediaBand::removeProxy(IUnknown *punkProxy) { if (_apContentProxies == NULL) return S_FALSE; HRESULT hr = S_FALSE; int cnt = _apContentProxies.GetPtrCount(); for (int i = 0; i < cnt; i++) { IContentProxy* pProxy = _apContentProxies.GetPtr(i); ASSERT(pProxy); if (pProxy) { if (SHIsSameObject(pProxy, punkProxy)) { _apContentProxies.DeletePtr(i); pProxy->Release(); ResetPlayer(); // privacy issue: // make sure player is stopped and proxy/behavior in next page cannot access current media _fAttached = FALSE; // force reattaching to player once a new behavior is up hr = S_OK; break; } } } return hr; } // IMediaHost2 //------------------------------------------------------------------------ STDMETHODIMP CMediaBand::OnDisableUIChanged(BOOL fDisabled) { return S_OK; } //------------------------------------------------------------------------ void CMediaBand::_AttachPlayerToProxies(BOOL fAttach) { if (_apContentProxies == NULL) return; if (_fAttached == fAttach) return; int cnt = _apContentProxies.GetPtrCount(); for (int i = 0; i < cnt; i++) { IContentProxy* pProxy = _apContentProxies.GetPtr(i); ASSERT(pProxy); if (pProxy) { HRESULT hr; if (fAttach) { hr = pProxy->OnCreatedPlayer(); } else { pProxy->detachPlayer(); hr = S_OK; } if (SUCCEEDED(hr)) { _fAttached = fAttach; } } } } //------------------------------------------------------------------------ void CMediaBand::_DetachProxies() { if (_apContentProxies == NULL) return; int cnt = _apContentProxies.GetPtrCount(); // need to iterate from last to first, call to removeProxy() will also remove it from DPA! for (int i = cnt - 1; i >= 0; i--) { IContentProxy* pProxy = _apContentProxies.GetPtr(i); ASSERT(pProxy); if (pProxy) { removeProxy(pProxy); } } _apContentProxies.Destroy(); return; } //------------------------------------------------------------------------ BOOL CMediaBand::_isUIDisabled() { if (_apContentProxies == NULL) return FALSE; int cnt = _apContentProxies.GetPtrCount(); BOOL fDisabled = FALSE; for (int i = 0; i < cnt; i++) { CComQIPtr pProxy = _apContentProxies.GetPtr(i); if (pProxy) { BOOL fQueryDisabled = FALSE; pProxy->IsDisableUIRequested(&fQueryDisabled); if (fQueryDisabled) { fDisabled = TRUE; break; } } } return fDisabled; } //------------------------------------------------------------------------ BOOL CMediaBand::_isProxiesNextEnabled() { if (_apContentProxies == NULL) return TRUE; int cnt = _apContentProxies.GetPtrCount(); BOOL fEnabled = TRUE; for (int i = 0; i < cnt; i++) { CComQIPtr pProxy = _apContentProxies.GetPtr(i); if (pProxy) { BOOL fQueryEnabled = FALSE; pProxy->IsNextEnabled(&fQueryEnabled); if (!fQueryEnabled) { fEnabled = FALSE; break; } } } return fEnabled; } //------------------------------------------------------------------------ void CMediaBand::_OnUserOverrideDisableUI() { if (_apContentProxies == NULL) return; int cnt = _apContentProxies.GetPtrCount(); BOOL fDisabled = FALSE; for (int i = 0; i < cnt; i++) { CComQIPtr pProxy = _apContentProxies.GetPtr(i); if (pProxy) { pProxy->OnUserOverrideDisableUI(); } } } //------------------------------------------------------------------------ void CMediaBand::_FireEventToProxies(enum contentProxyEvent event) { if (_apContentProxies == NULL) return; int cnt = _apContentProxies.GetPtrCount(); BOOL fDisabled = FALSE; for (int i = 0; i < cnt; i++) { IContentProxy* pProxy = _apContentProxies.GetPtr(i); ASSERT(pProxy); if (pProxy) { pProxy->fireEvent(event); } } } //------------------------------------------------------------------------ void CMediaBand::_CleanupStopTimer() { if (_idStopTimer != 0) { KillTimer(_hwnd, _idStopTimer); _idStopTimer = 0; // make sure user hasn't initiated another media action yet!!! SetPlayerControl(FCIDM_MEDIABAND_STOP, FALSE); } } //------------------------------------------------------------------------ HRESULT CMediaBand::_EnsureWMPInstalled(BOOL fShowErrorMsg) { HRESULT hr = S_OK; if (!CMediaBarUtil::IsWMP7OrGreaterInstalled()) { // ISSUE: assumption that XP already has matching WMP version if (!IsOS(OS_WHISTLERORGREATER)) { // try to web-jit WMP8. uCLSSPEC ucs; QUERYCONTEXT qc = { 0 }; ucs.tyspec = TYSPEC_CLSID; ucs.tagged_union.clsid = CLSID_JITWMP8; hr = FaultInIEFeature(_hwnd, &ucs, &qc, FIEF_FLAG_FORCE_JITUI); } if (!CMediaBarUtil::IsWMP7OrGreaterInstalled()) { // still no WMP, user might have aborted or install failed if (fShowErrorMsg) { MLShellMessageBox(_hwnd, MAKEINTRESOURCE(IDS_MEDIABAND_NOWMP7), MAKEINTRESOURCE(IDS_MEDIABAND_NOWMP7TITLE), MB_OK); } hr = E_UNEXPECTED; } } return hr; } // *** IBrowserBand methods *** STDMETHODIMP CMediaBand::GetObjectBB(REFIID riid, LPVOID *ppv) { return _spBrowser ? _spBrowser->QueryInterface(riid, ppv) : E_UNEXPECTED; } // *** IBandNavigate methods *** STDMETHODIMP CMediaBand::Select(LPCITEMIDLIST pidl) { _strDeferredURL.Empty(); // cancel any deferred navigation (usually during initial launch of mediabar return NavigateContentPane(pidl); } HRESULT CMediaBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi) { // aggregation checking is handled in class factory CMediaBand * pmb = new CMediaBand(); if (!pmb) return E_OUTOFMEMORY; // if you change this cast, fix up CChannelBand_CreateInstance *ppunk = SAFECAST(pmb, IDeskBand *); return S_OK; } //+------------------------------------------------------------------------- // Creates Player //-------------------------------------------------------------------------- BOOL CMediaBand::EnsurePlayer() { BOOL fResult = _pMediaPlayer ? TRUE : FALSE; if (!fResult) { fResult = CreatePlayer(); } return fResult && _pMediaPlayer; } BOOL CMediaBand::CreatePlayer() { HRESULT hr = CMediaBarPlayer_CreateInstance(IID_PPV_ARG(IMediaBarPlayer, &_pMediaPlayer)); if (SUCCEEDED(hr)) { hr = _pMediaPlayer->Init(_hwndLayout, SAFECAST(this, IMediaBar*)); if (SUCCEEDED(hr)) { hr = _pMediaPlayer->GetVideoHwnd(&_hwndVideo); } if (FAILED(hr)) { ASSERT(FALSE); DestroyPlayer(); } } return SUCCEEDED(hr); } VOID CMediaBand::DestroyPlayer() { _AttachPlayerToProxies(FALSE); if (_pMediaPlayer) { _pMediaPlayer->DeInit(); _pMediaPlayer->Release(); _pMediaPlayer = NULL; } _DetachProxies(); } // notifications from the player STDMETHODIMP CMediaBand::Notify(long lReason) { HRESULT hr = E_FAIL; if (EnsurePlayer()) { // update play/pause state TogglePlayPause(); if (!_fAttached) { _AttachPlayerToProxies(TRUE); } switch (lReason) { case DISPID_TIMESTATE_PROGRESS: { double dblProgress = _pMediaPlayer->GetTrackProgress(); if (!_fSeeking) { SetSeekPos(static_cast(dblProgress)); } // Update download/buffering progress, if any { ProgressType ProgType = PT_None; double dblBufProg = 0.0; hr = _pMediaPlayer->GetBufProgress(&dblBufProg, &ProgType); // S_OK only means that there's some buffering going on if ((hr == S_OK) && dblBufProg >= 0.0 && dblBufProg < 100.0) { SetStatusText(_szConnecting); } else { ShowPlayingStatus(); } if (TRUE == _pMediaPlayer->IsStreaming()) { // if this is streamed then substitute progress with track time // since progress is not meaningful dblProgress = _pMediaPlayer->GetTrackTime(); _UpdateTimeOutCounter(dblBufProg, dblProgress); } else { _UpdateTimeOutCounter(dblBufProg, dblProgress); } } } break; // case DISPID_TIMESTATE_PROGRESS case MEDIACOMPLETE: case TRACK_CHANGE: _fPlaying = TRUE; ShowPlayingStatus(TRUE); AdjustVideoHeight(TRUE); _EndTimeOutCounter(); SetPlayPause(_pMediaPlayer->IsPausePossible()); UpdateBackForwardControls(); if (ISVALIDWIDGET(_pmwSeek)) { _pmwSeek->SetState(_pMediaPlayer->IsSeekPossible()); } break; case MEDIA_TRACK_FINISHED: if (_iCurTrack != -1) { PlayNextTrack(); } else { _fSeeking = FALSE; ResetPlayer(); } break; case DISPID_TIMEMEDIAELEMENT_TITLE: _OnTitleChange(); ShowPlayingStatus(TRUE); break; } // switch (lReason) hr = S_OK; } // end if return hr; } STDMETHODIMP CMediaBand::OnMediaError(int iErrCode) { _EndTimeOutCounter(); if (-1 == iErrCode) { // if there is no rich erro info display the generic error message TCHAR szText[MAX_PATH]; szText[0] = TEXT('\0'); MLLoadString(IDS_MEDIABAND_INVALIDFILE, szText, ARRAYSIZE(szText)); SetStatusText(szText); } else { // ISSUE: to do: display the appropriate error message ASSERT(FALSE); } #ifdef PLAY_INDEFAULT // delegate the playback to the default player (fix for 24146) { // // ISSUE: What should we do for errors within a playlist?????? // CComBSTR sbstrUrl; if (EnsurePlayer() && SUCCEEDED(_pMediaPlayer->get_url(&sbstrUrl)) && (NULL != sbstrUrl.m_str)) { _OpenInDefaultPlayer(sbstrUrl); } } #endif return S_OK; } //+------------------------------------------------------------------------- // Handler for property change notification //-------------------------------------------------------------------------- void CMediaBand::_OnTitleChange() { // The status text and playlist menu should be updated here } //+------------------------------------------------------------------------- // Resize the video //-------------------------------------------------------------------------- void CMediaBand::_ResizeVideo(LONG* plWidth, LONG* plHeight) { if (EnsurePlayer() && _hwndVideo && ::IsWindow(_hwndVideo)) { _pMediaPlayer->Resize(plHeight, plWidth, FALSE); } } //+------------------------------------------------------------------------- // Redraw/show/hide the video window only if something has changed //-------------------------------------------------------------------------- VOID CMediaBand::AdjustVideoHeight(BOOL fForceResize) { VARIANT_BOOL vbHasVisual = VARIANT_FALSE; CComPtr spMediaElem; if (_pMediaPlayer && SUCCEEDED(_pMediaPlayer->get_mediaElement(&spMediaElem))) { // Show/hide the video display window if (SUCCEEDED(spMediaElem->get_hasVisual(&vbHasVisual))) { BOOL fVideo = (VARIANT_TRUE == vbHasVisual ? TRUE : FALSE) && _fPlaying; if (fVideo) { if (!IsWindowVisible(_hwndVideo) && !_fIsVideo) { ShowWindow(_hwndVideo, SW_SHOW); _fVideoAdjust = TRUE; _fIsVideo = TRUE; } } else { if (IsWindowVisible(_hwndVideo) && _fIsVideo) { _fVideoAdjust = TRUE; ShowWindow(_hwndVideo, SW_HIDE); _fIsVideo = FALSE; } } if (!_fVideoAdjust && fForceResize) { _fVideoAdjust = TRUE; } // redraw only if something has changed, so that this function can be called very often // (e.g. from Notify) without causing excessive drawing. if (_fVideoAdjust) { _fVideoAdjust = FALSE; if (_hwndPopup && IsWindowVisible(_hwndPopup)) { LONG lHeight = GetPopoutHeight(TRUE, _sizeVideo.cx); SetWindowPos(_hwndPopup, HWND_TOPMOST, 0, 0, _sizeLayout.cx, lHeight, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE); InvalidateRect(_hwndPopup, NULL, TRUE); ShowWindow(_hwndPopup, SW_SHOW); UpdateWindow(_hwndPopup); } else { RECT rcParent; GetClientRect(_hwnd, &rcParent); LONG lHeight = RECTHEIGHT(rcParent); lHeight = GetLayoutHeight(); AdjustLayout(RECTWIDTH(rcParent), lHeight); SendMessage(_hwnd, WM_SIZE, (WPARAM)0, (LPARAM) MAKELONG(RECTWIDTH(rcParent), lHeight)); } } } } } VOID CMediaBand::AdjustLayout(LONG_PTR lWidth, LONG_PTR lHeight) { RECT rcClient; if (!(_hwndPopup && IsWindowVisible(_hwndPopup))) { GetClientRect(_hwnd, &rcClient); if (lWidth<=MIN_WINDOW_WIDTH) { if (RECTWIDTH(rcClient) < MIN_WINDOW_WIDTH) lWidth = MIN_WINDOW_WIDTH ; else lWidth = RECTWIDTH(rcClient); } if (lHeight<=MIN_WINDOW_HEIGHT) { if (RECTHEIGHT(rcClient) < MIN_WINDOW_HEIGHT) lHeight = MIN_WINDOW_HEIGHT ; else lHeight = RECTHEIGHT(rcClient); } } _ResizeChildWindows(_hwndLayout, (LONG)lWidth, (LONG)lHeight, TRUE); } // IServiceProvider implementation HRESULT CMediaBand::QueryService(REFGUID guidService, REFIID riid, void ** ppvObj) { HRESULT hr = E_UNEXPECTED; if (IsEqualIID(guidService, SID_SMediaBar)) { hr = QueryInterface(riid, ppvObj); } else if (IsEqualIID(guidService, SID_SMediaBarSync)) { hr = QueryInterface(riid, ppvObj); } else if (IsEqualGUID(guidService, SID_SElementBehaviorFactory)) { hr = QueryInterface(riid, ppvObj); } else if (IsEqualGUID(guidService, SID_STimeContent)) { hr = QueryInterface(riid, ppvObj); } else { hr = SUPERCLASS::QueryService(guidService, riid, ppvObj); } return hr; } STDMETHODIMP CMediaBand::_TogglePause() { HRESULT hr = E_FAIL; if (EnsurePlayer()) { if (VARIANT_TRUE == _pMediaPlayer->isPaused()) { _fUserPaused = FALSE; if (SUCCEEDED(_pMediaPlayer->Resume())) { _BeginTimeOutCounter(); hr = S_OK; } } else { _fUserPaused = TRUE; hr = _pMediaPlayer->Pause(); if (SUCCEEDED(hr)) { _EndTimeOutCounter(); hr = S_OK; } } TogglePlayPause(); } return hr; } //+------------------------------------------------------------------------- // Creates and shows buttons //-------------------------------------------------------------------------- HRESULT CMediaBand::CreateControls() { // _pmwPlay _pmw[MW_PLAY] = CMediaWidgetButton_CreateInstance(_hwndLayout, 31, 33, FCIDM_MEDIABAND_PLAY, IDB_MEDIABAND_PLAY, IDB_MEDIABAND_PAUSE, IDS_MEDIABAND_PLAY, IDS_MEDIABAND_PAUSE); // _pmwStop _pmw[MW_STOP] = CMediaWidgetButton_CreateInstance(_hwndLayout, 18, 33, FCIDM_MEDIABAND_STOP, IDB_MEDIABAND_STOP, 0, IDS_MEDIABAND_STOP); // _pmwBack _pmw[MW_BACK] = CMediaWidgetButton_CreateInstance(_hwndLayout, 22, 16, FCIDM_MEDIABAND_PREVIOUS, IDB_MEDIABAND_BACK, 0, IDS_MEDIABAND_BACK); // _pmwNext _pmw[MW_NEXT] = CMediaWidgetButton_CreateInstance(_hwndLayout, 22, 16, FCIDM_MEDIABAND_NEXT, IDB_MEDIABAND_NEXT, 0, IDS_MEDIABAND_NEXT); _pmw[MW_MUTE] = new CMediaWidgetToggle(_hwndLayout, 22, 16); if (_pmwMute) { HRESULT hr = _pmwMute->Initialize(FCIDM_MEDIABAND_MUTE, IDS_MEDIABAND_UNMUTE, IDS_MEDIABAND_MUTE); if (SUCCEEDED(hr)) { hr = _pmwMute->SetImageList(IDB_MEDIABAND_MUTE); } if (SUCCEEDED(hr)) { hr = _pmwMute->SetAlternateImageList(IDB_MEDIABAND_MUTE); } _pmwMute->SetState(FALSE); if (FAILED(hr)) { delete _pmwMute; _pmw[MW_MUTE] = NULL; } } _pmw[MW_OPTIONS] = new CMediaWidgetOptions(_hwndLayout, 16, 16); if (_pmwOptions) { HRESULT hr = _pmwOptions->Initialize(FCIDM_MEDIABAND_MUTE, IDS_MEDIABAND_UNMUTE, IDS_MEDIABAND_MUTE); if (FAILED(hr)) { delete _pmwOptions; _pmw[MW_OPTIONS] = NULL; } } // _pmwPop _pmw[MW_POP] = CMediaWidgetButton_CreateInstance(_hwndLayout, 19, 20, FCIDM_MEDIABAND_POPOUT, IDB_MEDIABAND_POPOUT, IDB_MEDIABAND_POPIN, IDS_MEDIABAND_UNDOCK, IDS_MEDIABAND_DOCK); return S_OK; } HRESULT CMediaBand::CreateSeekBar() { DWORD dwWindowStyles = WS_TABSTOP | WS_VISIBLE | WS_CHILD | TBS_NOTICKS | TBS_FIXEDLENGTH; DWORD dwExStyle = WS_EX_TRANSPARENT; _hwndSeek = CreateWindowEx(dwExStyle, TRACKBAR_CLASS, NULL, dwWindowStyles, 0, 0, 0, 0, _hwndLayout, (HMENU) FCIDM_MEDIABAND_SEEK, HINST_THISDLL, NULL); if (_hwndSeek) { if (SetProp(_hwndSeek, c_szMediaBandProp, this)) { SetWindowLongPtr(_hwndSeek, GWLP_USERDATA, (LPARAM)(WNDPROC)(GetWindowLongPtr(_hwndSeek, GWLP_WNDPROC))); SetWindowLongPtr(_hwndSeek, GWLP_WNDPROC, (LPARAM)s_SeekWndSubClassProc); } SendMessage(_hwndSeek, TBM_SETRANGE, (WPARAM)TRUE , (LPARAM)MAKELONG(0, 100)); // min. & max. positions SendMessage(_hwndSeek, TBM_SETPAGESIZE, 0, (LPARAM)4); // new page size SendMessage(_hwndSeek, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)0); // ISSUE: For some reason, the length of the trackbar slider is screwed up, and the rect returned by the slider is half the actual width SendMessage(_hwndSeek, TBM_SETTHUMBLENGTH, (WPARAM)VOLUME_GRIPPER_LENGTH*2, 0); _himlSeekBack = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_MEDIABAND_SEEKBACK), SEEK_PART_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _himlSeekFill = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_MEDIABAND_SEEKFILL), SEEK_PART_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _pmw[MW_SEEK] = new CMediaWidgetSeek(); if (_pmwSeek) { _pmwSeek->Initialize(_hwndSeek); } Comctl32_SetDPIScale(_hwndSeek); ShowWindow(_hwndSeek, SW_SHOW); return S_OK; } else { return E_FAIL; } } HRESULT CMediaBand::CreateVolumeControl() { DWORD dwWindowStyles = WS_TABSTOP | WS_VISIBLE | WS_CHILD | TBS_NOTICKS | TBS_TOOLTIPS; DWORD dwExStyle = WS_EX_TRANSPARENT; _hwndVolume = CreateWindowEx(dwExStyle, TRACKBAR_CLASS, NULL, dwWindowStyles, 0, 0, 0, 0, _hwndLayout, (HMENU) FCIDM_MEDIABAND_VOLUME, HINST_THISDLL, NULL); if (_hwndVolume) { if (SetProp(_hwndVolume, c_szMediaBandProp, this)) { SetWindowLongPtr(_hwndVolume, GWLP_USERDATA, (LPARAM)(WNDPROC)(GetWindowLongPtr(_hwndVolume, GWLP_WNDPROC))); SetWindowLongPtr(_hwndVolume, GWLP_WNDPROC, (LPARAM)s_VolumeWndSubClassProc); } SendMessage(_hwndVolume, TBM_SETRANGE, (WPARAM)TRUE , (LPARAM)MAKELONG(0, 100)); // min. & max. positions SendMessage(_hwndVolume, TBM_SETPAGESIZE, 0, (LPARAM) 4); // new page size SendMessage(_hwndVolume, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)50); ShowWindow(_hwndVolume, SW_SHOW); _himlVolumeBack = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_MEDIABAND_VOLBKGND), VOLUME_BITMAP_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _himlVolumeFill = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_MEDIABAND_VOLFILL), VOLUME_BITMAP_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _himlGripper = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_MEDIABAND_VOLTAB), VOLUME_GRIPPER_LENGTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _pmw[MW_VOLUME] = new CMediaWidgetVolume; if (_pmwVolume) { _pmwVolume->Initialize(_hwndVolume); } return S_OK; } else { return E_FAIL; } } HRESULT CMediaBand::CreateLayoutPane() { if (!_hwndLayout) { WNDCLASS wndclass = { 0 }; wndclass.style = CS_PARENTDC; // | CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = s_LayoutWndProc; wndclass.hInstance = MLGetHinst(); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.lpszClassName = c_szMediaBarLayoutClassName; SHRegisterClass(&wndclass); _hwndLayout = CreateWindowEx(WS_EX_CONTROLPARENT, c_szMediaBarLayoutClassName, NULL, WS_TABSTOP | WS_VISIBLE | WS_CHILD, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, _hwnd, NULL, MLGetHinst(), (void *)this); if (_hwndLayout == NULL) { ASSERT(FALSE); return E_FAIL; } else { ::ShowWindow(_hwndLayout, SW_SHOW); } } return S_OK; } #define BACKGROUND_WIDTH (240/3) #define BACKGROUND_TOP 12 #define BACKGROUND_MIDDLE 2 #define BACKGROUND_BOTTOM 55 VOID CMediaBand::DrawBackground(HDC hdc, HWND hwnd) { if (_fHiColour) { HDC hdcSrc = CreateCompatibleDC(hdc); if (hdcSrc) { if (_hbmpBackground) { RECT rc; if (GetClientRect(hwnd, &rc)) { SelectObject(hdcSrc, _hbmpBackground); UINT xTra = 0; if (g_bRunOnMemphis && IS_WINDOW_RTL_MIRRORED(_hwnd)) { rc.right++; xTra++; } // We have 9 regions to paint. First we'll bitblt the corners, and then we'll do middle sections, which can be stretched without // loss of fidelity in a given direction. // |A|B|C| // |D|E|F| // |G|H|I| // Corners are bitblted // A BitBlt(hdc, rc.left, rc.top, BACKGROUND_WIDTH, BACKGROUND_TOP, hdcSrc, 0, 0, SRCCOPY); // C BitBlt(hdc, max(rc.right-BACKGROUND_WIDTH, rc.left+BACKGROUND_WIDTH), rc.top, BACKGROUND_WIDTH, BACKGROUND_TOP, hdcSrc, 2*BACKGROUND_WIDTH, 0, SRCCOPY); // G BitBlt(hdc, rc.left, max(rc.bottom-BACKGROUND_BOTTOM, rc.top+BACKGROUND_TOP), BACKGROUND_WIDTH, BACKGROUND_BOTTOM, hdcSrc, 0, BACKGROUND_TOP+BACKGROUND_MIDDLE, SRCCOPY); // I BitBlt(hdc, max(rc.right-BACKGROUND_WIDTH, rc.left+BACKGROUND_WIDTH), max(rc.bottom-BACKGROUND_BOTTOM, rc.top+BACKGROUND_TOP), BACKGROUND_WIDTH*2, BACKGROUND_BOTTOM, hdcSrc, BACKGROUND_WIDTH*2, BACKGROUND_TOP+BACKGROUND_MIDDLE, SRCCOPY); // Middles are all repeated/stetched if (rc.right-BACKGROUND_WIDTH > rc.left+BACKGROUND_WIDTH) { // B StretchBlt(hdc, rc.left+BACKGROUND_WIDTH, rc.top, RECTWIDTH(rc)-2*BACKGROUND_WIDTH+xTra, BACKGROUND_TOP, hdcSrc, BACKGROUND_WIDTH, 0, BACKGROUND_WIDTH, BACKGROUND_TOP, SRCCOPY); // H StretchBlt(hdc, rc.left+BACKGROUND_WIDTH, max(rc.bottom-BACKGROUND_BOTTOM, rc.top+BACKGROUND_TOP), RECTWIDTH(rc)-2*BACKGROUND_WIDTH+xTra, BACKGROUND_BOTTOM, hdcSrc, BACKGROUND_WIDTH, BACKGROUND_TOP+BACKGROUND_MIDDLE, BACKGROUND_WIDTH, BACKGROUND_BOTTOM, SRCCOPY); } if (rc.bottom-BACKGROUND_BOTTOM > rc.top+BACKGROUND_TOP) { // D StretchBlt(hdc, rc.left, rc.top+BACKGROUND_TOP, BACKGROUND_WIDTH, RECTHEIGHT(rc)-BACKGROUND_TOP-BACKGROUND_BOTTOM, hdcSrc, 0, BACKGROUND_TOP, BACKGROUND_WIDTH, BACKGROUND_MIDDLE, SRCCOPY); // F StretchBlt(hdc, max(rc.right-BACKGROUND_WIDTH, rc.left+BACKGROUND_WIDTH), rc.top+BACKGROUND_TOP, BACKGROUND_WIDTH, RECTHEIGHT(rc)-BACKGROUND_TOP-BACKGROUND_BOTTOM, hdcSrc, BACKGROUND_WIDTH*2, BACKGROUND_TOP, BACKGROUND_WIDTH, BACKGROUND_MIDDLE, SRCCOPY); // E // This section is one solid colour. if (rc.right-BACKGROUND_WIDTH > rc.left+BACKGROUND_WIDTH) { RECT rc2; rc2.left = rc.left+BACKGROUND_WIDTH; rc2.right = rc.right-BACKGROUND_WIDTH; rc2.top = rc.top+BACKGROUND_TOP; rc2.bottom = rc.bottom-BACKGROUND_BOTTOM; SHFillRectClr(hdc, &rc2, COLOR_BKGNDMIDDLE); } } } } DeleteDC(hdcSrc); } } else { RECT rc; if (GetClientRect(hwnd, &rc)) { SHFillRectClr(hdc, &rc, COLOR_BKGND16); } } if (_hwndVideo && IsWindowVisible(_hwndVideo)) { RedrawWindow(_hwndVideo, NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE); } } // WndProc for main window to go in rebar LRESULT CALLBACK CMediaBand::s_LayoutWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { CMediaBand* pmb = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); if (msg==WM_CREATE) { SetWindowLongPtr(hWnd, GWLP_USERDATA, (reinterpret_cast((reinterpret_cast(lParam))->lpCreateParams))); return 0; } else if (pmb) { switch (msg) { case WM_PAINT: { break; } case WM_ERASEBKGND: pmb->DrawBackground((HDC)wParam, hWnd); return TRUE; case WM_SIZE: if ((LONG)LOWORD(lParam) <= 0 || (LONG)HIWORD(lParam) <= 0 ) break; pmb->AdjustLayout(LOWORD(lParam), HIWORD(lParam)); break; case WM_SYSCOLORCHANGE: case WM_WININICHANGE: { BOOL fNewColours = (SHGetCurColorRes() > 8); if (fNewColours!=pmb->_fHiColour) { pmb->SwitchBitmaps(fNewColours); } pmb->AdjustVideoHeight(TRUE); } break; case WM_VSCROLL: case WM_HSCROLL: if ((HWND)lParam == pmb->_hwndSeek) { SendMessage(pmb->_hwndSeek, msg, wParam, lParam); } else if ((HWND)lParam == pmb->_hwndVolume) { SendMessage(pmb->_hwndVolume, msg, wParam, lParam); } break; case WM_NOTIFY: { LRESULT lres; if (pmb->OnNotify((LPNMHDR)lParam, &lres)) { return lres; } break; } break; case WM_COMMAND: { LRESULT lres; if (pmb->OnWinEvent(hWnd, msg, wParam, lParam, &lres) == S_OK) return lres; } break; } } return DefWindowProc(hWnd, msg, wParam, lParam); } HRESULT CMediaBand::CreateParentPane() { if (!_hwnd) { WNDCLASS wndclass = { 0 }; wndclass.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = s_WndProc; wndclass.hInstance = MLGetHinst(); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.lpszClassName = c_szMediaBarClassName; SHRegisterClass(&wndclass); _hwnd = CreateWindowEx(WS_EX_CONTROLPARENT, c_szMediaBarClassName, NULL, WS_TABSTOP | WS_VISIBLE | WS_CHILD, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, _hwndParent, NULL, MLGetHinst(), (void *)this); if (_hwnd == NULL) { ASSERT(FALSE); return E_FAIL; } else { ::ShowWindow(_hwnd, SW_SHOW); } } return S_OK; } VOID CMediaBand::Resize(HWND hwnd, LONG lWidth, LONG lHeight) { if (lWidth <= 0 || lHeight <= 0) return; RECT rcParent; if (GetClientRect(_hwnd, &rcParent)) { if (IsWindowVisible(_hwndPopup)) { MoveWindow(_hwndContent, rcParent.left, rcParent.top, RECTWIDTH(rcParent), RECTHEIGHT(rcParent), FALSE); } else { LONG lPaneHeight = GetLayoutHeight(); MoveWindow(_hwndLayout, rcParent.left, rcParent.bottom-lPaneHeight, lWidth, lPaneHeight, FALSE); MoveWindow(_hwndContent, rcParent.left, rcParent.top, lWidth, RECTHEIGHT(rcParent)-lPaneHeight, FALSE); InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); } } } // WndProc for main window to go in rebar LRESULT CALLBACK CMediaBand::s_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { CMediaBand* pmb = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); switch (msg) { case WM_ERASEBKGND: break; case WM_CREATE: SetWindowLongPtr(hWnd, GWLP_USERDATA, (reinterpret_cast((reinterpret_cast(lParam))->lpCreateParams))); return 0; case WM_SIZE: if (pmb) { pmb->Resize(hWnd, (LONG)LOWORD(lParam), (LONG)HIWORD(lParam)); } break; case WM_MB_DEFERRED_NAVIGATE: // navigation cancelled by IBandNavigate::ISelect() call if (pmb && (pmb->_strDeferredURL.Length() > 0)) { pmb->NavigateContentPane(pmb->_strDeferredURL); pmb->_strDeferredURL.Empty(); } break; case WM_NOTIFY: if (pmb) { return pmb->_OnNotify((LPNMHDR)lParam); } break; case WM_COMMAND: { LRESULT lres; if (pmb->OnWinEvent(hWnd, msg, wParam, lParam, &lres) == S_OK) return lres; } case WM_TIMER: // timeout of user's second chance to click stop again and navigate to media content pane to default URL if (pmb) { pmb->_CleanupStopTimer(); } break; case WM_WTSSESSION_CHANGE: // stop playing media when media bar is no more in current terminal server session // this avoids "background noise" when user does fast user switching to other login in XP // NOTE: logging on as same user remotely will also stop stream if (pmb && ((wParam == WTS_CONSOLE_DISCONNECT) || (wParam == WTS_REMOTE_DISCONNECT))) { pmb->Exec(&CLSID_MediaBand, FCIDM_MEDIABAND_STOP, 0, NULL, NULL); } break; break; } return DefWindowProc(hWnd, msg, wParam, lParam); } LRESULT CALLBACK CMediaBand::s_PopupWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CMediaBand* pmb = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); switch (uMsg) { case WM_CREATE: ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams); break; case WM_ACTIVATE: if (pmb) { pmb->ActivatePopout(LOWORD(wParam)!=WA_INACTIVE); } return 0; case WM_KEYDOWN: if (wParam==VK_ESCAPE) { pmb->DockMediaPlayer(); } break; case WM_GETMINMAXINFO: // prevent it from getting too small or too large if (pmb) { pmb->ComputeMinMax((MINMAXINFO *)lParam); } break; case WM_SIZE: if (pmb && IsWindowVisible(hwnd)) { SetWindowPos(pmb->_hwndLayout, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOACTIVATE); // MoveWindow(pmb->_hwndLayout, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); } break; case WM_SYSCOMMAND : if (wParam == SC_CLOSE) pmb->DockMediaPlayer(); break; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } VOID CMediaBand::ActivatePopout(BOOL fState) { _fPopoutHasFocus = fState; UIActivateIO(fState, NULL); } VOID CMediaBand::ComputeMinMax(MINMAXINFO *pMinMax) { pMinMax->ptMinTrackSize.x = GetMinPopoutWidth(); if (_fIsVideo) { pMinMax->ptMinTrackSize.y = GetPopoutHeight(FALSE) + VIDEO_MIN_HEIGHT; } else { pMinMax->ptMaxTrackSize.y = pMinMax->ptMinTrackSize.y = GetPopoutHeight(FALSE); } } LRESULT CALLBACK CMediaBand::s_VolumeWndSubClassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CMediaBand* pmb = (CMediaBand*)GetProp(hwnd, c_szMediaBandProp); if (!pmb) return DefWindowProcWrap(hwnd, uMsg, wParam, lParam); WNDPROC pfnOldWndProc = (WNDPROC)(GetWindowLongPtr(hwnd, GWLP_USERDATA)); switch (uMsg) { case WM_HSCROLL: case WM_VSCROLL: { INT_PTR lPos = SendMessage(hwnd, TBM_GETPOS, (WPARAM) 0 ,(LPARAM) 0); switch (LOWORD(wParam)) { case TB_THUMBPOSITION: case TB_THUMBTRACK: { if (pmb != NULL) { pmb->_dblVol = (double)lPos; if (pmb->_pMediaPlayer) { pmb->_pMediaPlayer->put_volume(pmb->_dblVol); } } InvalidateRect(hwnd,NULL,TRUE); UpdateWindow(hwnd); } break ; case TB_TOP: { if (pmb) { pmb->_dblVol = 0; if (pmb->_pMediaPlayer) { pmb->_pMediaPlayer->put_volume(0); } } } break; case TB_BOTTOM: { if (pmb) { pmb->_dblVol = 100; if (pmb->_pMediaPlayer) { pmb->_pMediaPlayer->put_volume(100); } } } break; } } break; case WM_DESTROY: { // // Unsubclass myself. // RemoveProp(hwnd, c_szMediaBandProp); if (pfnOldWndProc) { SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) pfnOldWndProc); } } break; } return CallWindowProc(pfnOldWndProc, hwnd, uMsg, wParam, lParam); } LRESULT CALLBACK CMediaBand::s_SeekWndSubClassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CMediaBand* pmb = (CMediaBand*)GetProp(hwnd, c_szMediaBandProp); if (!pmb) return DefWindowProcWrap(hwnd, uMsg, wParam, lParam); WNDPROC pfnOldWndProc = (WNDPROC)(GetWindowLongPtr(hwnd, GWLP_USERDATA)); switch (uMsg) { case WM_ERASEBKGND: break; case WM_HSCROLL: { if (pmb && pmb->_pMediaPlayer && pmb->_fPlaying) { if (pmb->_pMediaPlayer->IsSeekPossible() && !pmb->_isUIDisabled()) { INT_PTR lPos = SendMessage(hwnd, TBM_GETPOS, (WPARAM) 0 ,(LPARAM) 0); switch (LOWORD(wParam)) { case TB_THUMBPOSITION: { pmb->_fSeeking = FALSE; pmb->Seek(lPos / 100.0); if (!pmb->_fUserPaused) { pmb->_pMediaPlayer->Resume(); } } break; case TB_THUMBTRACK: { pmb->_fSeeking = TRUE; if (!pmb->_fUserPaused) { pmb->_pMediaPlayer->Pause(); } pmb->Seek(lPos / 100.0); InvalidateRect(hwnd,NULL,TRUE); UpdateWindow(hwnd); } break; case TB_PAGEUP: case TB_TOP: { double dblProgress = pmb->_pMediaPlayer->GetTrackProgress(); // seek backwards by 5% pmb->Seek(dblProgress - 0.05); } break; case TB_PAGEDOWN: case TB_BOTTOM: { double dblProgress = pmb->_pMediaPlayer->GetTrackProgress(); // seek ahead by 5% pmb->Seek(dblProgress + 0.05); } break; } } else { // disallow seeking by setting the seek position to what it was double dblProgress = pmb->_pMediaPlayer->GetTrackProgress(); pmb->SetSeekPos(static_cast(dblProgress)); } } } break; case WM_DESTROY: { // // Unsubclass myself. // RemoveProp(hwnd, c_szMediaBandProp); if (pfnOldWndProc) { SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) pfnOldWndProc); } } break; } return CallWindowProc(pfnOldWndProc, hwnd, uMsg, wParam, lParam); } // sends appropriate resize messages to our children windows VOID CMediaBand::_ResizeChildWindows(HWND hwnd, LONG width, LONG height, BOOL fRepaint) { // Calculate the display rectangle RECT rc; SIZE sizeTB = {0}, sizePopout = {0}; LONG lHorzSpacing = MIN_HORZ_SPACING; _sizeLayout.cx = width; _sizeLayout.cy = GetLayoutHeight(); SetRect(&rc, 0, 0, width, height); LONG lWidthOffset = rc.left+lHorzSpacing; HDWP hdwp = BeginDeferWindowPos(10); lWidthOffset = rc.left+lHorzSpacing; if (_fIsVideo && _hwndVideo) { LONG lWidth, lHeight, lVideoStart = 0; if (_hwndPopup && IsWindowVisible(_hwndPopup)) { lWidth = width-rc.left-lHorzSpacing*2; lHeight = GetVideoHeight(); } else { lWidth = SCALEX(MIN_WINDOW_WIDTH-rc.left-lHorzSpacing*2); lHeight = SCALEY(MIN_WINDOW_WIDTH-rc.left); } // Resize the video and try to get the video sizes _ResizeVideo(&lWidth,&lHeight); _sizeVideo.cx = (LONG)lWidth ; _sizeVideo.cy = (LONG)lHeight ; if (lWidth >= width-rc.left-lHorzSpacing*2) lVideoStart = rc.left + lHorzSpacing; else lVideoStart = (width-rc.left-lHorzSpacing*2-lWidth)/2 + rc.left + lHorzSpacing ; DeferWindowPos(hdwp, _hwndVideo, HWND_TOP, (LONG)lVideoStart, rc.top+VIEW_MARGIN_TOP_VIDEO, (LONG)lWidth, (LONG)lHeight, SWP_NOZORDER); } else { _sizeVideo.cx = 0 ; _sizeVideo.cy = 0; } // Bottom-most row LONG lHeightOffset = height - VIEW_MARGIN_BOTTOM; lWidthOffset = rc.left + VIEW_MARGIN_LEFT; LONG lSeekY = lHeightOffset, lSeekX = 0; if (_pmwPlay && _pmwPlay->_hwnd) { GetToolbarSize(_pmwPlay->_hwnd, &sizeTB); lSeekY = lHeightOffset-sizeTB.cy; DeferWindowPos(hdwp, _pmwPlay->_hwnd, HWND_TOP, lWidthOffset, lHeightOffset-sizeTB.cy, sizeTB.cx, sizeTB.cy, SWP_NOZORDER); lWidthOffset += sizeTB.cx; } if (_pmwStop && _pmwStop->_hwnd) { GetToolbarSize(_pmwStop->_hwnd, &sizeTB); DeferWindowPos(hdwp, _pmwStop->_hwnd, HWND_TOP, lWidthOffset, lHeightOffset-sizeTB.cy, sizeTB.cx, sizeTB.cy, SWP_NOZORDER); lWidthOffset += sizeTB.cx; } if (_pmwBack && _pmwBack->_hwnd) { GetToolbarSize(_pmwBack->_hwnd, &sizeTB); lSeekX = lWidthOffset; DeferWindowPos(hdwp, _pmwBack->_hwnd, HWND_TOP, lWidthOffset, lHeightOffset-sizeTB.cy, sizeTB.cx, sizeTB.cy, SWP_NOZORDER); lWidthOffset += sizeTB.cx; } if (_pmwNext && _pmwNext->_hwnd) { GetToolbarSize(_pmwNext->_hwnd, &sizeTB); DeferWindowPos(hdwp, _pmwNext->_hwnd, HWND_TOP, lWidthOffset, lHeightOffset-sizeTB.cy, sizeTB.cx, sizeTB.cy, SWP_NOZORDER); lWidthOffset += sizeTB.cx; } if (_pmwMute && _pmwMute->_hwnd) { GetToolbarSize(_pmwMute->_hwnd, &sizeTB); LONG lVolumeWidth = SCALEX(MIN_VOLUME_WIDTH); lWidthOffset = max(lWidthOffset+lHorzSpacing, (width - sizeTB.cx - lVolumeWidth - VIEW_MARGIN_RIGHT)); DeferWindowPos(hdwp, _pmwMute->_hwnd, HWND_TOP, lWidthOffset, lHeightOffset-sizeTB.cy, sizeTB.cx, sizeTB.cy, SWP_NOZORDER); if (_hwndVolume) { lWidthOffset += sizeTB.cx; DeferWindowPos(hdwp, _hwndVolume, HWND_TOP, lWidthOffset, lHeightOffset-sizeTB.cy, lVolumeWidth, SCALEY(MIN_VOLUME_HEIGHT), SWP_NOZORDER); } } lWidthOffset = rc.left + lHorzSpacing; if (_hwndSeek) { LONG lSeekWidth = max(width-lHorzSpacing-lSeekX-2, 0); DeferWindowPos(hdwp, _hwndSeek, HWND_TOP, lSeekX+2, lSeekY, lSeekWidth, SCALEY(SEEK_HEIGHT), SWP_NOZORDER); } lWidthOffset = rc.left + VIEW_MARGIN_INFO_LEFT; if (ISVALIDWIDGET(_pmwPop)) { GetToolbarSize(_pmwPop->_hwnd, &sizePopout); DeferWindowPos(hdwp, _pmwPop->_hwnd, HWND_TOP, width-sizePopout.cx-VIEW_MARGIN_INFO_LEFT, lSeekY-sizePopout.cy-VIEW_CONTROLS_MARGIN, sizePopout.cx, sizePopout.cy, SWP_NOZORDER); } if (ISVALIDWIDGET(_pmwOptions)) { GetToolbarSize(_pmwOptions->_hwnd, &sizeTB); DeferWindowPos(hdwp, _pmwOptions->_hwnd, HWND_TOP, lWidthOffset, lSeekY-sizeTB.cy-VIEW_CONTROLS_MARGIN, width-lHorzSpacing*3-sizePopout.cx, sizeTB.cy, SWP_NOZORDER); _iOptionsWidth = width-lHorzSpacing*3-sizePopout.cx-10; SendMessage(_pmwOptions->_hwnd, TB_SETBUTTONWIDTH, 0, (LPARAM) MAKELONG(0, _iOptionsWidth)); SendMessage(_pmwOptions->_hwnd, TB_AUTOSIZE, 0, 0); } EndDeferWindowPos(hdwp); if (fRepaint) { InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); } else { InvalidateRect(hwnd, NULL, FALSE); UpdateWindow(hwnd); } } LONG CMediaBand::GetControlsHeight() { LONG lHeightOffset = VIEW_MARGIN_TOP; // Compute height for options here if (ISVALIDWIDGET(_pmwOptions)) { SIZE sizeTB = {0}; GetToolbarSize(_pmwOptions->_hwnd, &sizeTB); lHeightOffset += SCALEY(sizeTB.cy) + VIEW_CONTROLS_MARGIN; } // Rest of controls lHeightOffset += VIEW_MARGIN_BOTTOM + SCALEY(VIEW_CONTROLS_HEIGHT); return lHeightOffset; } LONG CMediaBand::GetLayoutHeight(LONG lWidth) { LONG lHeightOffset = GetControlsHeight(); if (_hwndVideo && (IsWindowVisible(_hwndVideo) || _fIsVideo)) { LONG lHeight = GetVideoHeight(lWidth); if (lHeight>0) lHeightOffset += lHeight + VIEW_MARGIN_TOP_VIDEO; } return lHeightOffset; } float CMediaBand::GetSeekPos() { INT_PTR lMax = SendMessage(_hwndSeek, TBM_GETRANGEMAX, 0, 0) ; INT_PTR lMin = SendMessage(_hwndSeek, TBM_GETRANGEMIN, 0, 0) ; INT_PTR lPos = SendMessage(_hwndSeek, TBM_GETPOS, 0, 0) ; return ((float)lPos / (float)(lMax - lMin)); } VOID CMediaBand::SetSeekPos(float fPosition) { INT_PTR lMax = SendMessage(_hwndSeek, TBM_GETRANGEMAX, 0, 0) ; INT_PTR lMin = SendMessage(_hwndSeek, TBM_GETRANGEMIN, 0, 0) ; fPosition *= (lMax - lMin) ; INT_PTR lPos = SendMessage(_hwndSeek, TBM_GETPOS, 0, 0) ; if (lPos!=(LONG) fPosition) { SendMessage(_hwndSeek, TBM_SETPOS, TRUE, (LPARAM) (LONG) fPosition); InvalidateRect(_hwndSeek, NULL,TRUE); UpdateWindow(_hwndSeek); } } HRESULT CMediaBand::_InitializeMediaUI() { HRESULT hr = S_OK; _fHiColour = (SHGetCurColorRes() > 8); if (!_hwndLayout) { CreateLayoutPane(); } if (!_hwndContent) { InitContentPane(); } if (!_fInitialized && _hwndLayout) { _szConnecting[0] = TEXT('\0'); MLLoadString(IDS_MEDIABAND_NOWDOWNLOADING, _szConnecting, ARRAYSIZE(_szConnecting)); _hbmpBackground = LoadBitmap(HINST_THISDLL, MAKEINTRESOURCE(IDB_MEDIABAND_BG_BASE)); CreateControls(); CreateSeekBar(); CreateVolumeControl(); ResetPlayer(); if (!_fHiColour) { // Assume high colour. If not, switch to low colour versions. SwitchBitmaps(_fHiColour); } // want to sink notification when fast user switch occurs: WTSRegisterSessionNotification(_hwnd, NOTIFY_FOR_THIS_SESSION); _fInitialized = TRUE; } _ShowAllWindows(TRUE); return hr; } VOID CMediaBand::_ShowAllWindows(BOOL fShow) { if (_hwndPopup && IsWindowVisible(_hwndPopup)) { // SendMessage(_hwndPopup, WM_SYSCOMMAND, (WPARAM)SC_CLOSE, (LPARAM)0); return; } if (_hwndLayout) ShowWindow(_hwndLayout, fShow ? SW_SHOW : SW_HIDE); for (int i=0; i < ARRAYSIZE(_pmw); i++) { if (ISVALIDWIDGET(_pmw[i])) ShowWindow(_pmw[i]->_hwnd, fShow ? SW_SHOW : SW_HIDE); } if (_hwndContent) { ShowWindow(_hwndContent, fShow ? SW_SHOW : SW_HIDE); } } VOID CMediaBand::ToggleMute() { _fMuted = !_fMuted; if (_pmwMute) { _pmwMute->SetState(_fMuted); } if (_pMediaPlayer) { _pMediaPlayer->put_mute(_fMuted); } } VOID CMediaBand::TogglePlayPause() { if (!EnsurePlayer()) { return; } VARIANT_BOOL vbPaused = _pMediaPlayer->isPaused(); VARIANT_BOOL vbStopped = _pMediaPlayer->isStopped(); // if player is in paused state, show the play button and vice-versa // _fPlayButton==FALSE means that the pause button is currently displayed // _fPlayButton==TRUE means that the play button is currently displayed if (vbStopped || vbPaused) { if (!_fPlayButton) { _fPlayButton = TRUE; if (_pmwPlay) { _pmwPlay->SetMode(MWB_NORMAL); _pmwPlay->SetImageSource(TRUE); } } } else { if (_fPlayButton) { _fPlayButton = FALSE; if (_pMediaPlayer->IsPausePossible()) { // ISSUE (akabir): The following line doesn't work correctly // _pmwPlay->SetMode(MWB_DISABLED); } // change button bitmaps if (_pmwPlay) { _pmwPlay->SetImageSource(FALSE); } } } } HWND CMediaBand::GetBrowserWindow() { CComPtr spWebBrowser; // QS for the browser main window if (SUCCEEDED(QueryService(SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &spWebBrowser)))) { LONG_PTR hwndApp; if (SUCCEEDED(spWebBrowser->get_HWND(&hwndApp))) { return ((HWND)hwndApp); } } return NULL; } // Called only by CMediaBand::CreateInstance HRESULT CMediaBand::InitPlayerPopup() { HRESULT hr = E_FAIL; WNDCLASS wndclass = { 0 }; wndclass.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = s_PopupWndProc; wndclass.hInstance = HINST_THISDLL; wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.lpszClassName = c_szMediaBarPopupClassName; wndclass.hIcon = (HICON)LoadIcon(HINST_THISDLL, MAKEINTRESOURCE(IDB_TB_MEDIA_HOT)); wndclass.hbrBackground = NULL; SHRegisterClass(&wndclass); DWORD dwStyle = (WS_OVERLAPPEDWINDOW & ~(WS_MINIMIZEBOX)); DWORD dwExStyle = WS_EX_CONTROLPARENT | (IS_BIDI_LOCALIZED_SYSTEM() ? dwExStyleRTLMirrorWnd : 0); _hwndPopup = CreateWindowEx(dwExStyle, c_szMediaBarPopupClassName, NULL, dwStyle, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, GetBrowserWindow(), NULL, HINST_THISDLL, (void *)this); hr = (_hwndPopup && _hwndLayout) ? S_OK : E_FAIL; // modify the properties of the window as appropriate if (SUCCEEDED(hr)) { // set parent SHSetParentHwnd(_hwndLayout, _hwndPopup); WCHAR szTitle[256]; MLLoadStringW(IDS_MEDIABANDTEXT, szTitle, ARRAYSIZE(szTitle)); SetWindowText(_hwndPopup, szTitle); if (_sizeLayout.cx < GetMinPopoutWidth()) _sizeLayout.cx = GetMinPopoutWidth(); if (_fSavedPopoutState) { SetWindowPlacement(_hwndPopup, &_wpPopout); } else { RECT rc = { 0 }; INT iHeight = GetPopoutHeight(TRUE, _sizeLayout.cx); INT x = 10, y = 10; if (GetWindowRect(_hwnd, &rc)) { x = IS_WINDOW_RTL_MIRRORED(_hwnd) ? (rc.right - _sizeLayout.cx) : rc.left; y = rc.bottom - iHeight; if (y < 0) { y = rc.bottom; } } SetWindowPos(_hwndPopup, HWND_TOPMOST, x, y, _sizeLayout.cx, iHeight, SWP_FRAMECHANGED | SWP_SHOWWINDOW); } ShowWindow(_hwndPopup, SW_SHOW); UpdateWindow(_hwndPopup); if (_pmwPop && _pmwPop->_hwnd) { _pmwPop->SetImageSource(FALSE); if (_iElement==MW_POP) { _fPopoutHasFocus = TRUE; UIActivateIO(TRUE, NULL); } } } return hr; } HRESULT CMediaBand::GetTrackTitle(BSTR *pbstrTitle) { USES_CONVERSION; CComPtr spMediaElem; HRESULT hr = E_FAIL; if ( !EnsurePlayer() || !pbstrTitle) { hr = E_FAIL; goto done; } *pbstrTitle = NULL; // // if a title is available from the media element, display it // hr = _pMediaPlayer->get_mediaElement(&spMediaElem); if ( FAILED(hr) || !spMediaElem.p) { hr = E_FAIL; goto done; } hr = spMediaElem->get_title(pbstrTitle); if (SUCCEEDED(hr) && (*pbstrTitle != NULL)) { if (SysStringLen(*pbstrTitle)>0) { goto done; } else { SysFreeString(*pbstrTitle); *pbstrTitle = NULL; } } // // if title is not available, display the the url // hr = _pMediaPlayer->get_url(pbstrTitle); if (SUCCEEDED(hr) && *pbstrTitle && (SysStringLen(*pbstrTitle)<=0)) { SysFreeString(*pbstrTitle); *pbstrTitle = NULL; } if (SUCCEEDED(hr) && (*pbstrTitle != NULL)) { // If the url is available, display it DWORD dwcchUnescaped; TCHAR tszPath[MAX_PATH]; StrCpyN(tszPath, W2T(*pbstrTitle), ARRAYSIZE(tszPath)); PathStripPath(tszPath); if (SUCCEEDED(UrlUnescape(tszPath, NULL, &dwcchUnescaped, URL_UNESCAPE_INPLACE))) { SysFreeString(*pbstrTitle); *pbstrTitle = SysAllocString(tszPath); } } hr = S_OK; done: return hr; } VOID CMediaBand::ShowPlayingStatus(BOOL fInitial) { USES_CONVERSION; BSTR bstrTitle = NULL; if (EnsurePlayer() && _fPlaying) { if (!_isUIDisabled()) { GetTrackTitle(&bstrTitle); // Display the name of the title if (bstrTitle && bstrTitle[0] != 0) SetStatusText(W2T(bstrTitle)); } else { TCHAR szText[MAX_PATH]; szText[0] = TEXT('\0'); MLLoadString(IDS_MEDIABAND_PLAYING, szText, ARRAYSIZE(szText)); SetStatusText(szText); } CComPtr spMediaElem; HRESULT hr = _pMediaPlayer->get_mediaElement(&spMediaElem); ERROREXIT(hr) // store away the natural length of the media hr = spMediaElem->get_mediaDur(&_dblMediaDur); ERROREXIT(hr) } done : if (bstrTitle) SysFreeString(bstrTitle); } VOID CMediaBand::SetStatusText(LPTSTR lpwStatusInfo) { if (ISVALIDWIDGET(_pmwOptions)) { // change buttons TBBUTTONINFO tbbi; TCHAR szText[MAX_PATH]; tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_BYINDEX | TBIF_TEXT; tbbi.pszText = szText ; tbbi.cchText = MAX_PATH ; SendMessage(_pmwOptions->_hwnd, TB_GETBUTTONINFO, (WPARAM)0, (LPARAM)&tbbi); if (StrCmpIW(tbbi.pszText,lpwStatusInfo)) { tbbi.pszText = lpwStatusInfo; if (_pszStatus) { delete [] _pszStatus; } _pszStatus = new TCHAR[lstrlen(lpwStatusInfo)+1]; if (_pszStatus) { StringCchCopy(_pszStatus, ARRAYSIZE(_pszStatus), lpwStatusInfo); } SendMessage(_pmwOptions->_hwnd, TB_SETBUTTONINFO, (WPARAM)0, (LPARAM)&tbbi); // Need to force a resizing to accommodate new text SendMessage(_pmwOptions->_hwnd, TB_SETBUTTONWIDTH, 0, (LPARAM) MAKELONG(0, _iOptionsWidth-1)); SendMessage(_pmwOptions->_hwnd, TB_SETBUTTONWIDTH, 0, (LPARAM) MAKELONG(0, _iOptionsWidth)); } } } HRESULT CMediaBand::ShowPlayListMenu(HWND hwnd, RECTL* rc) { if (_hPlayListMenu) { DestroyMenu(_hPlayListMenu); _hPlayListMenu = NULL; } _hPlayListMenu = GetSubMenu(LoadMenu(MLGetHinst(), MAKEINTRESOURCE(MENU_MEDIA_GENERIC)), 0); if (_EnumPlayItems() != S_OK) { DestroyMenu(_hPlayListMenu); _hPlayListMenu = NULL; return S_OK; } ASSERT(_pMediaPlayer); UINT nID = FCIDM_PLAYITEM_START + (UINT)_pMediaPlayer->GetPlayListItemIndex(); CheckMenuRadioItem(_hPlayListMenu, FCIDM_PLAYITEM_START, FCIDM_PLAYITEM_END, nID, MF_BYCOMMAND); UpdateMenuItems(_hPlayListMenu); POINT pt = {rc->left ,rc->bottom}; int idCmd = TrackPopupMenu(_hPlayListMenu, TPM_LEFTBUTTON | TPM_TOPALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL); if (idCmd>=FCIDM_PLAYITEM_START && idCmd<=FCIDM_PLAYITEM_END) { UINT iCurTrack = idCmd - FCIDM_PLAYITEM_START ; _pMediaPlayer->SetActiveTrack(iCurTrack); UpdateBackForwardControls(); } else { HandleMenuTasks(idCmd); } return S_OK; } STDMETHODIMP CMediaBand::_EnumPlayItems() { USES_CONVERSION; CComPtr spMediaElem; CComPtr spPlayList; CComVariant svarIndex; long lLength = 0; INT i = 0; MENUITEMINFO mii = { sizeof(mii) }; HRESULT hr = _pMediaPlayer->get_mediaElement(&spMediaElem); ERROREXIT(hr) hr = spMediaElem->get_playList(&spPlayList); ERROREXIT(hr) if (!(spPlayList.p)) return S_FALSE; hr = spPlayList->get_length(&lLength); ERROREXIT(hr) svarIndex.vt = VT_I4; mii.cbSize = sizeof(mii); mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; mii.fType = MFT_STRING | MFT_RADIOCHECK; mii.fState = MF_ENABLED; for (; i < lLength; i++) { CComPtr spPlayItem; CComBSTR sbstrTitle; TCHAR wszPath[40]; V_I4(&svarIndex) = i; hr = spPlayList->item(svarIndex, &spPlayItem); ERROREXIT(hr) hr = spPlayItem->get_title(&sbstrTitle); ERROREXIT(hr) mii.wID = i + FCIDM_PLAYITEM_START; if (sbstrTitle.Length() != 0) { StrCpyN(wszPath, sbstrTitle, ARRAYSIZE(wszPath)); } else { CComBSTR sbstrSrc; if (SUCCEEDED(spPlayItem->get_src(&sbstrSrc)) && sbstrSrc.Length() != 0) { PWSTR psz = PathFindFileName(sbstrSrc); StrCpyN(wszPath, psz, ARRAYSIZE(wszPath)); } else { WCHAR szTemplate[64]; if (!MLLoadStringW(IDS_MEDIABAND_TRACKNUMBER, szTemplate, ARRAYSIZE(szTemplate))) { StrCpy(szTemplate, TEXT("%d")); } wnsprintf(wszPath, ARRAYSIZE(wszPath), szTemplate, i+1); } } mii.dwTypeData = (LPTSTR)wszPath; InsertMenuItem(_hPlayListMenu, i, TRUE, &mii); } mii.fMask = MIIM_TYPE; mii.fType = MFT_SEPARATOR; InsertMenuItem(_hPlayListMenu, i, TRUE, &mii); hr = S_OK; done: return hr; } HRESULT CMediaBand::ShowGenericMenu(HWND hwnd, RECTL* rc) { HMENU hMenu = GetSubMenu(LoadMenu(MLGetHinst(), MAKEINTRESOURCE(MENU_MEDIA_GENERIC)), 0); if (hMenu) { UpdateMenuItems(hMenu); int idCmd = TrackPopupMenu(hMenu, TPM_LEFTBUTTON | TPM_TOPALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, rc->left, rc->bottom, 0, hwnd, NULL); HandleMenuTasks(idCmd); DestroyMenu(hMenu); } return S_OK; } HRESULT CMediaBand::HandleMenuTasks(INT idCmd) { switch (idCmd) { case IDM_MEDIA_PLAYINDEFAULT: { CComBSTR sbstrUrl; if (SUCCEEDED(_pMediaPlayer->get_url(&sbstrUrl)) && (NULL != sbstrUrl.m_str)) { _OpenInDefaultPlayer(sbstrUrl); } } break; case IDM_MEDIA_ADDTOFAVORITES: { BSTR bstr = NULL, bstrTitle = NULL; if (EnsurePlayer() && !_isUIDisabled() && SUCCEEDED(_pMediaPlayer->get_url(&bstr)) && bstr && SUCCEEDED(GetTrackTitle(&bstrTitle))) { if (*bstr) { AddToFavorites(bstr, bstrTitle); } SysFreeString(bstr); } break; } case IDM_MEDIA_PLAYINBAR: ToggleAutoplay(!GetAutoplay()); break; case IDM_MEDIA_ASKTYPES: ToggleAutoplayPrompting(!GetAutoplayPrompt()); break; case IDM_MEDIA_RESETTYPES: ResetMimePreferences(); break; case IDM_MEDIA_TAKEOVERTYPES: if (PromptSettings(IDD_MEDIA_TAKEOVERMIMEPROMPT)) { // do take over file types here } break; case IDM_MEDIA_RADIO_GOTO: _NavigateMainWindow(c_szRadioUrl); break; case IDM_MEDIA_BROADBAND_GUIDE: NavigateMoreMedia(); break; } return S_OK; } HRESULT CMediaBand::_NavigateMainWindow(LPCTSTR wstrUrl, bool fSuppressFirstAutoPlay /* = false */) { CComPtr spWB2; // QS for the media bar HRESULT hr = QueryService(SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &spWB2)); if (SUCCEEDED(hr)) { CComBSTR sbstrUrl(wstrUrl); CComVariant svarEmpty; if (fSuppressFirstAutoPlay) { hr = CMediaBarHelper::DisableFirstAutoPlay(spWB2); if (FAILED(hr)) goto done; } if (sbstrUrl) { hr = spWB2->Navigate(sbstrUrl, &svarEmpty, &svarEmpty, &svarEmpty, &svarEmpty); } else { hr = E_OUTOFMEMORY; } } done: return hr; } HRESULT CMediaBand::ResetMimePreferences() { HRESULT hr = S_OK; if (PromptSettings(IDD_MEDIA_RESETMIMEPROMPT)) { DWORD dwRet = SHDeleteKey(HKEY_CURRENT_USER, WZ_SMIE_MEDIA_MIME); if (ERROR_SUCCESS != dwRet) { hr = E_FAIL; } } return hr; } BOOL CMediaBand::PromptSettings(UINT IDPROMPT) { return (DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDPROMPT), GetBrowserWindow(), s_PromptMimeDlgProc, NULL) == IDOK); } INT_PTR CALLBACK CMediaBand::s_PromptMimeDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_COMMAND: if (GET_WM_COMMAND_ID(wParam, lParam)==IDC_MEDIA_MOREINFO) { SHHtmlHelpOnDemandWrap(GetParent(hDlg), TEXT("iexplore.chm > iedefault"), 0, (DWORD_PTR) TEXT("mediabar_settings.htm"), ML_CROSSCODEPAGE); } else { EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam)); } break; } return FALSE; } HRESULT CMediaBand::AddToFavorites(BSTR bstrUrl, BSTR bstrTitle) { HRESULT hr = E_FAIL; if (_hwndPopup && IsWindowVisible(_hwndPopup)) { DockMediaPlayer(); } if (bstrUrl) { CComPtr spShellUIHelper; hr = CoCreateInstance(CLSID_ShellUIHelper, NULL, CLSCTX_INPROC_SERVER, IID_IShellUIHelper, (void**) &spShellUIHelper); if (SUCCEEDED(hr)) { CComVariant svarTitle(bstrTitle); hr = spShellUIHelper->AddFavorite(bstrUrl, &svarTitle); } } return hr; } LONG CMediaBand::GetVideoHeight(LONG lSpecifiedWidth, BOOL fNewVideo) { LONG lPaneWidth = lSpecifiedWidth==0 ? SCALEX(MIN_WINDOW_WIDTH) : lSpecifiedWidth; LONG lWidth = lPaneWidth-MIN_HORZ_SPACING*2, lHeight = lWidth; // Assumption: Video is never taller than it is wide if (_hwndPopup && IsWindowVisible(_hwndPopup)) { RECT rcWindow; GetClientRect(_hwndPopup,&rcWindow); lPaneWidth = RECTWIDTH(rcWindow); // minimum widths as per spec lWidth = lPaneWidth - MIN_HORZ_SPACING * 2; // Allow for controls. if (fNewVideo) { lHeight = lWidth; } else { lHeight = RECTHEIGHT(rcWindow)-GetControlsHeight()-VIEW_MARGIN_TOP_VIDEO; } } // Resize the video and get video sizes _ResizeVideo(&lWidth,&lHeight); if (lWidth != -1 || lHeight != -1) return (lHeight>0 ? lHeight : (lPaneWidth-MIN_HORZ_SPACING*5)) ; else return -1; } VOID CMediaBand::DockMediaPlayer() { if (!_hwndPopup) { InitPlayerPopup(); } else if (IsWindowVisible(_hwndPopup)) { // map the system window close request into a redocking operation instead // of closing _wpPopout.length = sizeof(_wpPopout); _fSavedPopoutState = GetWindowPlacement(_hwndPopup, &_wpPopout); // set the parent back to embedded window SHSetParentHwnd(_hwndLayout, _hwnd); DestroyWindow(_hwndPopup); _hwndPopup = NULL; if (_pmwPop && _pmwPop->_hwnd) { _pmwPop->SetImageSource(TRUE); } } RECT rcParent; GetClientRect(_hwnd, &rcParent); SendMessage(_hwnd, WM_SIZE, (WPARAM)0, (LPARAM)MAKELONG(RECTWIDTH(rcParent), RECTHEIGHT(rcParent))); InvalidateRect(_hwnd, NULL, TRUE); UpdateWindow(_hwnd); } VOID CMediaBand::GetToolbarSize(HWND hwndTB, SIZE *pSize) { int nButtons = ToolBar_ButtonCount(hwndTB); pSize->cx = 0 ; pSize->cy = 0 ; for (int nIndex = 0; nIndex < nButtons; nIndex++) { RECTL rc ; SendMessage(hwndTB, TB_GETITEMRECT, nIndex, (LPARAM)&rc); pSize->cx += RECTWIDTH(rc); pSize->cy = max(RECTHEIGHT(rc),pSize->cy); } } //+------------------------------------------------------------------------- // Name: Invoke, IDispatch // // Abstract: // This switches on the dispid looking for dispid's of events // that it should handle. Note, this is called for all events // fired from the window, only the selected events are handled. //-------------------------------------------------------------------------- STDMETHODIMP CMediaBand::Invoke( /* [in] */ DISPID dispidMember, /* [in] */ REFIID /*riid*/, /* [in] */ LCID /*lcid*/, /* [in] */ WORD /*wFlags*/, /* [out][in] */ DISPPARAMS* pdispparams, /* [out] */ VARIANT* pVarResult, /* [out] */ EXCEPINFO* /*pExcepInfo*/, /* [out] */ UINT* puArgErr) { USES_CONVERSION; HRESULT hr = E_FAIL; if (!pdispparams) return E_INVALIDARG; // show our friendly 404 page on navigation error: if (dispidMember == DISPID_NAVIGATEERROR) { // validate expected param list if ( (pdispparams->cArgs != 5) || (pdispparams->rgvarg[4].vt != VT_DISPATCH) // IWebBrowser2 as IDispatch || (pdispparams->rgvarg[3].vt != (VT_BYREF | VT_VARIANT)) // target URL as BSTR || (pdispparams->rgvarg[2].vt != (VT_BYREF | VT_VARIANT)) // target frame as BSTR || (pdispparams->rgvarg[1].vt != (VT_BYREF | VT_VARIANT)) // status code as VT_I4 || (pdispparams->rgvarg[0].vt != (VT_BYREF | VT_BOOL))) // Cancel as VT_BOOL, OUT param { ASSERTMSG(0, "unexpected param list for NavigateError"); return E_INVALIDARG; } LPCTSTR pszURL = W2CT(VariantToStrCast(&pdispparams->rgvarg[3])); int iStatus = VariantToInt(pdispparams->rgvarg[1]); // can't navigate to page, give help page TCHAR szResURL[2*MAX_URL_STRING]; // expect URL to help page and original URL HRESULT hr; hr = _BuildPageURLWithParam(c_sz404URL, pszURL, szResURL, ARRAYSIZE(szResURL)); if (FAILED(hr)) { return hr; } // navigate deferred, caller of this Invoke() will cancel the current navigation _DeferredNavigate(szResURL); // have our own page, cancel the std error page: ASSERT(pdispparams->rgvarg[0].vt == (VT_BYREF | VT_BOOL)); *V_BOOLREF(&pdispparams->rgvarg[0]) = VARIANT_TRUE; } // just for additional leak protection: give up proxy refs if not done already // before we get out of current document context if (dispidMember == DISPID_BEFORENAVIGATE) { _DetachProxies(); } return S_OK; } LRESULT CMediaBand::_OnVolumeCustomDraw(LPNMCUSTOMDRAW pnm) { RECT rcClient; GetClientRect(pnm->hdr.hwndFrom, &rcClient); switch (pnm->dwDrawStage) { case CDDS_PREPAINT: return CDRF_NOTIFYITEMDRAW; case CDDS_PREERASE: return CDRF_NOTIFYITEMDRAW; case CDDS_ITEMPREPAINT: { HDC hdc = (HDC)pnm->hdc; RECT rcFill; SendMessage(pnm->hdr.hwndFrom, TBM_GETCHANNELRECT, (WPARAM)0, (LPARAM)(LPRECT)&rcFill); RECT rcThumb; SendMessage(pnm->hdr.hwndFrom, TBM_GETTHUMBRECT, 0L, (LPARAM)&rcThumb); SHFillRectClr(hdc, &rcClient, _fHiColour ? COLOR_BKGND : COLOR_BKGND16); UINT uFlags = ILD_TRANSPARENT | (IsOS(OS_WHISTLERORGREATER) ? ILD_DPISCALE : 0); if (_himlVolumeBack) { ImageList_Draw(_himlVolumeBack, 0, hdc, rcClient.left, rcClient.top, uFlags); } if (_himlVolumeFill) { ImageList_DrawEx(_himlVolumeFill, 0, hdc, rcClient.left, rcClient.top, rcThumb.left, SEEK_HEIGHT, 0, 0, uFlags); } if (_himlGripper) { ImageList_Draw(_himlGripper, 0, hdc, rcThumb.left, 0, uFlags); } } return CDRF_SKIPDEFAULT; } return CDRF_DODEFAULT; } LRESULT CMediaBand::_OnSeekBarCustomDraw(LPNMCUSTOMDRAW pnm) { RECT rcClient; GetClientRect(pnm->hdr.hwndFrom, &rcClient); switch (pnm->dwDrawStage) { case CDDS_PREPAINT: return CDRF_NOTIFYITEMDRAW; case CDDS_PREERASE: return CDRF_NOTIFYITEMDRAW; case CDDS_ITEMPREPAINT: { HDC hdc = (HDC)pnm->hdc; SHFillRectClr(hdc, &rcClient, _fHiColour ? COLOR_BKGND2 : COLOR_BKGND16); RECT rcFill; SendMessage(pnm->hdr.hwndFrom, TBM_GETCHANNELRECT, (WPARAM)0, (LPARAM)(LPRECT)&rcFill); RECT rcThumb; SendMessage(pnm->hdr.hwndFrom, TBM_GETTHUMBRECT, 0L, (LPARAM)&rcThumb); int x, y = 1+(SEEK_HEIGHT-SEEK_PART_HEIGHT)/2; UINT uFlags = ILD_TRANSPARENT | (IsOS(OS_WHISTLERORGREATER) ? ILD_DPISCALE : 0); // always draw background with progress if (_himlSeekBack) { INT lPartWidth = SCALEX(SEEK_PART_WIDTH); x = rcFill.left; ImageList_Draw(_himlSeekBack, 0, hdc, x, y, uFlags); x = rcFill.right - lPartWidth; int inx = rcFill.left + lPartWidth; while (inx < x) { ImageList_Draw(_himlSeekBack, 1, hdc, inx, y, uFlags); inx += lPartWidth; } ImageList_Draw(_himlSeekBack, 2, hdc, x, y, uFlags); } if (pnm->dwItemSpec==TBCD_THUMB) { if ((!(pnm->uItemState & CDIS_DISABLED)) && ISVALIDWIDGET(_pmwSeek) && _pmwSeek->IsEnabled()) { x = rcFill.left; int seekWidth = rcThumb.left-x; if (_himlSeekFill && seekWidth) { if (seekWidth < SEEK_PART_WIDTH) { ImageList_DrawEx(_himlSeekFill, 0, hdc, x, y, seekWidth, SEEK_PART_HEIGHT, 0, 0, uFlags); } else { ImageList_Draw(_himlSeekFill, 0, hdc, x, y, uFlags); x += SEEK_PART_WIDTH; while ((rcThumb.left-x)>0) { ImageList_DrawEx(_himlSeekFill, 1, hdc, x, y, min(SEEK_PART_WIDTH, (rcThumb.left-x)), SEEK_PART_HEIGHT, 0, 0, uFlags); x += SEEK_PART_WIDTH; } } } INT iState = MWB_NORMAL; if (pnm->uItemState & CDIS_SELECTED) { iState = MWB_PRESSED; } else if (pnm->uItemState & CDIS_HOT) { iState = MWB_HOT; } if (_himlGripper) { ImageList_Draw(_himlGripper, iState, hdc, rcThumb.left, 0, uFlags); } } } } return CDRF_SKIPDEFAULT; } return CDRF_DODEFAULT; } LONG CMediaBand::GetPopoutHeight(BOOL fMeasureVideo, LONG lWidth) { LONG lHeight = (fMeasureVideo ? GetLayoutHeight(lWidth) : GetControlsHeight()) + GetSystemMetrics(SM_CYSIZE) + GetSystemMetrics(SM_CYEDGE)*2 + GetSystemMetrics(SM_CYSIZEFRAME)*2; return lHeight; } LONG CMediaBand::GetMinPopoutWidth() { return MIN_POPOUT_WIDTH + (GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXFRAME))*2; } BOOL CMediaBand::ResetPlayer() { _iCurTrack = -1; _fPlaying = FALSE; if (ISVALIDWIDGET(_pmwSeek)) { _pmwSeek->SetState(FALSE); } if (_pMediaPlayer) { _pMediaPlayer->Stop(); SetSeekPos(0.0); TogglePlayPause(); if (_hwndVideo && IsWindowVisible(_hwndVideo)) { _fIsVideo = FALSE; ShowWindow(_hwndVideo, SW_HIDE); } AdjustVideoHeight(TRUE); } TCHAR szTitle[MAX_PATH]; MLLoadStringW(IDS_MEDIABAND_MYMUSIC, szTitle, ARRAYSIZE(szTitle)); SetStatusText(szTitle); SetPlayerControl(FCIDM_MEDIABAND_PREVIOUS, FALSE); SetPlayerControl(FCIDM_MEDIABAND_NEXT, FALSE); // while timer is running , give user a second chance to click stop again and reset media content pane if (_idStopTimer == 0) { SetPlayerControl(FCIDM_MEDIABAND_STOP, FALSE); } SetPlayPause(TRUE); return TRUE; } HRESULT CMediaBand::PlayLocalTrack(int iTrackNum) { HRESULT hr = E_FAIL; if (_ppidls && (iTrackNum < (int)_cidls)) { // to avoid pot. privacy leak, unload mediabar behavior if (_IsProxyRunning()) { // user clicked on a media link in the main content pane, unfreeze controls! _OnUserOverrideDisableUI(); _DetachProxies(); _NavigateContentToDefaultURL(); } TCHAR szFile[MAX_PATH]; if (SUCCEEDED(SHGetNameAndFlags(_ppidls[iTrackNum], SHGDN_FORPARSING, szFile, ARRAYSIZE(szFile), NULL))) { _iCurTrack = iTrackNum; if (EnsurePlayer()) _PutUrl(szFile, NULL); hr = S_OK; } } return hr; } HRESULT CMediaBand::PlayNextTrack() { if (EnsurePlayer() && (_iCurTrack != -1)) { LONG_PTR lCurTrack = _pMediaPlayer->GetPlayListItemIndex(); LONG_PTR lItemCount = _pMediaPlayer->GetPlayListItemCount(); if ((lItemCount <= 1) || (lCurTrack == lItemCount - 1)) { PlayLocalTrack(_iCurTrack + 1); } else { ResetPlayer(); } } return S_OK; } BOOL CMediaBand::SetPlayerControl(UINT ui, BOOL fState) { CMediaWidget* pmw = NULL; switch (ui) { case FCIDM_MEDIABAND_PREVIOUS: // while UI frozen by mediabar behavior, previous is always disabled if (fState && _pMediaPlayer) { fState = _pMediaPlayer->IsSkippable(); } if (_isUIDisabled()) { fState = FALSE; // override to always disable } pmw = _pmwBack; break; case FCIDM_MEDIABAND_NEXT: // only override if any of the proxies are running if (fState && _pMediaPlayer) { fState = _pMediaPlayer->IsSkippable(); } if (_apContentProxies != NULL) { if (_isUIDisabled() && _pMediaPlayer && !_pMediaPlayer->IsSeekPossible()) { fState = FALSE; } // only force a disabled next button if stream has NOSKIP attribute set if (!_isProxiesNextEnabled()) { fState = FALSE; } } pmw = _pmwNext; break; case FCIDM_MEDIABAND_STOP: pmw = _pmwStop; break; default: ASSERT(FALSE); break; } if (pmw && pmw->_hwnd) { SendMessage(pmw->_hwnd, TB_ENABLEBUTTON, ui, MAKELONG(fState, 0)); } return TRUE; } BOOL CMediaBand::UpdateBackForwardControls() { BOOL fPrevious = FALSE, fNext = FALSE; if (_iCurTrack != -1) { fPrevious = _iCurTrack != 0; fNext = ((_iCurTrack + 1) < (int)_cidls); } else if (EnsurePlayer()) { LONG_PTR lItemCount= _pMediaPlayer->GetPlayListItemCount(); if (lItemCount > 1) { LONG_PTR lCurTrack = _pMediaPlayer->GetPlayListItemIndex(); fPrevious = (lCurTrack > 0); fNext = lCurTrack < lItemCount - 1; } } SetPlayerControl(FCIDM_MEDIABAND_PREVIOUS, fPrevious); SetPlayerControl(FCIDM_MEDIABAND_NEXT, fNext); return TRUE; } HRESULT CMediaBand::Seek(double dblProgress) { HRESULT hr = S_OK; if (EnsurePlayer()) { hr = _pMediaPlayer->Seek(dblProgress); if (SUCCEEDED(hr)) { // play/pause state may have been changed by Seek TogglePlayPause(); } } return hr; } LPTSTR CMediaBand::GetUrlForStatusBarToolTip() { USES_CONVERSION; LPTSTR szRet = NULL; if (_pMediaPlayer) { if (_pMediaPlayer->isStopped()) { return _pszStatus; } CComBSTR sbstrUrl; HRESULT hr = _pMediaPlayer->get_url(&sbstrUrl); if ( SUCCEEDED(hr) && (sbstrUrl.m_str) && (sbstrUrl.Length()>0)) { szRet = W2T(sbstrUrl); if (szRet) { // // The tooltip structure (NMTTDISPINFO.lpszText) requires a pointer to a private buffer. // Store the pointer so we can free it later. // int len = lstrlen(szRet); delete [] _szToolTipUrl; _szToolTipUrl = new TCHAR[len + 1]; if (_szToolTipUrl) { memcpy(_szToolTipUrl, szRet, sizeof(TCHAR) * (len + 1)); } szRet = _szToolTipUrl; } } } return szRet; } VOID CMediaBand::UpdateMenuItems(HMENU hmenu) { ASSERT(hmenu); CComBSTR sbstrUrl; if (GetAutoplay()) { CheckMenuItem(hmenu, IDM_MEDIA_PLAYINBAR, MF_BYCOMMAND | MF_CHECKED); } if (GetAutoplayPrompt()) { CheckMenuItem(hmenu, IDM_MEDIA_ASKTYPES, MF_BYCOMMAND | MF_CHECKED); } if (!_pMediaPlayer || _pMediaPlayer->isStopped() || FAILED(_pMediaPlayer->get_url(&sbstrUrl)) || !sbstrUrl.m_str || (sbstrUrl.Length()<=0) || _isUIDisabled()) { DeleteMenu(hmenu, IDM_MEDIA_PLAYINDEFAULT, MF_BYCOMMAND); DeleteMenu(hmenu, IDM_MEDIA_ADDTOFAVORITES, MF_BYCOMMAND); DeleteMenu(hmenu, 0, MF_BYPOSITION); } } BOOL CMediaBand::OnNotify(LPNMHDR pnm, LRESULT* plres) { ASSERT(plres); BOOL fRet = FALSE; switch (pnm->code) { case NM_CUSTOMDRAW: { LRESULT lres; LPNMCUSTOMDRAW pnmc = (LPNMCUSTOMDRAW)pnm; if (pnm->hwndFrom == _hwndVolume) { lres = _OnVolumeCustomDraw(pnmc); } else if (pnm->hwndFrom == _hwndSeek) { lres = _OnSeekBarCustomDraw(pnmc); } else { for (int i=0; ihwndFrom == _pmw[i]->_hwnd)) { lres = _pmw[i]->Draw((LPNMTBCUSTOMDRAW)pnm); } } } fRet = TRUE; *plres = lres; } break; case TBN_DROPDOWN: { LPNMTOOLBAR lpnmTB = ((LPNMTOOLBAR)pnm); HWND hwndTB = pnm->hwndFrom; UINT nCmdID = lpnmTB->iItem; // figure out coordinates to use INT_PTR iBtn = SendMessage(hwndTB, TB_GETHOTITEM, 0, 0); RECTL rc ; SendMessage(hwndTB, TB_GETITEMRECT, iBtn, (LPARAM)&rc); MapWindowPoints(hwndTB, HWND_DESKTOP, (LPPOINT)&rc , 2); if (_pmwOptions && hwndTB==_pmwOptions->_hwnd) { if (_pMediaPlayer && (_pMediaPlayer->GetPlayListItemCount() > 0) && !_pMediaPlayer->isStopped() && !_isUIDisabled() && _pMediaPlayer->IsSkippable()) { ShowPlayListMenu(hwndTB, &rc); } else { ShowGenericMenu(hwndTB, &rc); } } else { VARIANTARG var; var.vt = VT_I4; var.lVal = MAKELONG(rc.left, rc.bottom); *plres = Exec(&CLSID_MediaBand, nCmdID, 0, &var, NULL); fRet = TRUE; } // end of else } break; case TBN_GETDISPINFO: { LPNMTBDISPINFO lptbi = (LPNMTBDISPINFO)pnm; if (lptbi->hdr.hwndFrom == _pmwPlay->_hwnd && lptbi->dwMask & TBNF_IMAGE) { TBBUTTONINFO tbbi; tbbi.dwMask = TBIF_COMMAND | TBIF_STATE; SendMessage(lptbi->hdr.hwndFrom, TB_GETBUTTONINFO, (WPARAM)lptbi->idCommand, (LPARAM)&tbbi); if (_fPlayButton) lptbi->iImage = (!(tbbi.fsState & TBSTATE_INDETERMINATE) && (tbbi.fsState & TBSTATE_PRESSED)) ? 3 : 1 ; else lptbi->iImage = (!(tbbi.fsState & TBSTATE_INDETERMINATE) && (tbbi.fsState & TBSTATE_PRESSED)) ? 2 : 0 ; lptbi->dwMask |= TBNF_DI_SETITEM; } else if (_pmwOptions && (lptbi->hdr.hwndFrom ==_pmwOptions->_hwnd)) { lptbi->iImage = 0; lptbi->dwMask |= TBNF_DI_SETITEM; } } break; case TTN_GETDISPINFO: { LPNMTTDISPINFO pnmtt = (LPNMTTDISPINFO)pnm; pnmtt->hinst = MLGetHinst(); switch (pnmtt->hdr.idFrom) { case FCIDM_MEDIABAND_POPOUT: pnmtt->lpszText = (PTSTR)MAKEINTRESOURCE(_hwndPopup ? IDS_MEDIABAND_DOCK : IDS_MEDIABAND_UNDOCK); break; case FCIDM_MEDIABAND_PLAY: pnmtt->lpszText = (PTSTR)MAKEINTRESOURCE(_fPlayButton ? IDS_MEDIABAND_PLAY : IDS_MEDIABAND_PAUSE); break; case FCIDM_MEDIABAND_MUTE: pnmtt->lpszText = (PTSTR)MAKEINTRESOURCE(_fMuted ? IDS_MEDIABAND_UNMUTE : IDS_MEDIABAND_MUTE); break; case FCIDM_MEDIABAND_PLAYINFO: { if (_pMediaPlayer && !_isUIDisabled()) { LPTSTR szUrl = GetUrlForStatusBarToolTip(); if (szUrl) { pnmtt->lpszText = szUrl; } } break; } } } } return fRet; } HRESULT CMediaBand::_OpenInDefaultPlayer(BSTR bstrUrl) { HRESULT hr = E_FAIL; if ( !bstrUrl || !(*bstrUrl)) { hr = E_FAIL; goto done; } // suppress first autoplay and navigate main IE window hr = _NavigateMainWindow(bstrUrl, true); if (FAILED(hr)) { goto done; } if (_hwndPopup && IsWindowVisible(_hwndPopup)) { DockMediaPlayer(); } // pause/stop the playback if (_pMediaPlayer->IsPausePossible()) { _pMediaPlayer->Pause(); } else { _pMediaPlayer->Stop(); } hr = S_OK; done: return hr; } VOID CMediaBand::SetPlayPause(BOOL fState) { _fPlayEnabled = fState; if (_pmwPlay && _pmwPlay->_hwnd) { SendMessage(_pmwPlay->_hwnd, TB_SETSTATE, FCIDM_MEDIABAND_PLAY, MAKELONG((_fPlayEnabled ? TBSTATE_ENABLED : 0), 0)); InvalidateRect(_pmwPlay->_hwnd, NULL, FALSE); UpdateWindow(_pmwPlay->_hwnd); } } INT idNormalHi[MW_NUMBER] = { IDB_MEDIABAND_PLAY, // MW_PLAY = 0, IDB_MEDIABAND_STOP, // MW_STOP, IDB_MEDIABAND_BACK, // MW_BACK, IDB_MEDIABAND_NEXT, // MW_NEXT, IDB_MEDIABAND_MUTE, // MW_MUTE, IDB_MEDIABAND_VOLBKGND, // MW_VOLUME, 0, // MW_OPTIONS, IDB_MEDIABAND_POPOUT, // MW_POP, IDB_MEDIABAND_SEEKBACK, // MW_SEEK, }; INT idAltHi[MW_NUMBER] = { IDB_MEDIABAND_PAUSE, // MW_PLAY = 0, 0, // MW_STOP, 0, // MW_BACK, 0, // MW_NEXT, 0, // MW_MUTE, IDB_MEDIABAND_VOLFILL, // MW_VOLUME, 0, // MW_OPTIONS, IDB_MEDIABAND_POPIN, // MW_POP, IDB_MEDIABAND_SEEKFILL, // MW_SEEK, }; INT idNormalLo[MW_NUMBER] = { IDB_MEDIABAND_PLAY16, // MW_PLAY = 0, IDB_MEDIABAND_STOP16, // MW_STOP, IDB_MEDIABAND_BACK16, // MW_BACK, IDB_MEDIABAND_NEXT16, // MW_NEXT, IDB_MEDIABAND_MUTE16, // MW_MUTE, IDB_MEDIABAND_VOLBKGND16, // MW_VOLUME, 0, // MW_OPTIONS, IDB_MEDIABAND_POPOUT16, // MW_POP, IDB_MEDIABAND_SEEKBACK16, // MW_SEEK, }; INT idAltLo[MW_NUMBER] = { IDB_MEDIABAND_PAUSE16, // MW_PLAY = 0, 0, // MW_STOP, 0, // MW_BACK, 0, // MW_NEXT, 0, // MW_MUTE, IDB_MEDIABAND_VOLFILL16, // MW_VOLUME, 0, // MW_OPTIONS, IDB_MEDIABAND_POPIN16, // MW_POP, IDB_MEDIABAND_SEEKFILL16, // MW_SEEK, }; VOID CMediaBand::SwitchBitmaps(BOOL fNewSetting) { INT* idAlt = fNewSetting ? idAltHi : idAltLo; INT* idNormal = fNewSetting ? idNormalHi : idNormalLo; for (int i=0; iSetDepth(fNewSetting); } break; case MW_VOLUME: DESTROY_OBJ_WITH_HANDLE(_himlVolumeBack, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_himlVolumeFill, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_himlGripper, ImageList_Destroy); _himlVolumeBack = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(idNormal[i]), VOLUME_BITMAP_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _himlVolumeFill = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(idAlt[i]), VOLUME_BITMAP_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _himlGripper = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(fNewSetting ? IDB_MEDIABAND_VOLTAB : IDB_MEDIABAND_VOLTAB16), 6, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); break; default: // The rest are buttons { CMediaWidgetButton* pmwb = (CMediaWidgetButton*)_pmw[i]; pmwb->SetImageList(idNormal[i]); if (idAlt[i]) { pmwb->SetAlternateImageList(idAlt[i]); } } break; } } } _fHiColour = fNewSetting; InvalidateRect(_hwnd, NULL, TRUE); UpdateWindow(_hwnd); } VOID CMediaBand::InitContentPane() { SHDRC shdrc = {sizeof(SHDRC), SHDRCF_OCHOST}; shdrc.cbSize = sizeof (SHDRC); shdrc.dwFlags |= SHDRCF_OCHOST; if (_hwnd && IsWindow(_hwnd) && DllRegisterWindowClasses(&shdrc)) { // Create an OCHost window _hwndContent = CreateWindow(OCHOST_CLASS, NULL, WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_TABSTOP, 0, 0, 0, 0, _hwnd, NULL, HINST_THISDLL, NULL); if (_hwndContent) { OCHINITSTRUCT ocs; ocs.cbSize = SIZEOF(OCHINITSTRUCT); ocs.clsidOC = CLSID_WebBrowser; ocs.punkOwner = SAFECAST(this, IDispatch*); if (SUCCEEDED(OCHost_InitOC(_hwndContent, (LPARAM)&ocs))) { OCHost_QueryInterface(_hwndContent, IID_PPV_ARG(IWebBrowser2, &_spBrowser)); OCHost_QueryInterface(_hwndContent, IID_PPV_ARG(IOleInPlaceActiveObject, &_poipao)); OCHost_DoVerb(_hwndContent, OLEIVERB_INPLACEACTIVATE, FALSE); _ConnectToCP(TRUE); } _NavigateContentToDefaultURL(); } } } HRESULT CMediaBand::_ConnectToCP(BOOL fConnect) { // get ready to sink the OCHost's browser events if (!_spBrowser) { return E_FAIL; } if (!fConnect && (_dwcpCookie == 0)) { return S_FALSE; // } return ConnectToConnectionPoint(SAFECAST(this, IDispatch*), DIID_DWebBrowserEvents2, fConnect, _spBrowser, &_dwcpCookie, NULL); } HRESULT CMediaBand::NavigateContentPane(BSTR bstrUrl) { HRESULT hr = E_FAIL; if (_spBrowser && bstrUrl) { _strCurrentContentUrl = bstrUrl; CComVariant svarEmpty; svarEmpty.vt = VT_NULL; hr = _spBrowser->Navigate(bstrUrl, &svarEmpty, &svarEmpty, &svarEmpty, &svarEmpty); } return hr; } HRESULT CMediaBand::NavigateContentPane(LPCITEMIDLIST pidl) { HRESULT hr = E_FAIL; if (_spBrowser && pidl) { TCHAR szURL[MAX_URL_STRING]; if (SUCCEEDED(::IEGetDisplayName(pidl, szURL, SHGDN_FORPARSING))) { _strCurrentContentUrl = szURL; } else { _strCurrentContentUrl.Empty(); } CComVariant svarEmpty; svarEmpty.vt = VT_NULL; CComVariant varURL; InitVariantFromIDList(&varURL, pidl); hr = _spBrowser->Navigate2(&varURL, &svarEmpty, &svarEmpty, &svarEmpty, &svarEmpty); } return hr; } VOID CMediaBand::NavigateMoreMedia() { _NavigateMainWindow(c_szMoreMediaUrl); } HRESULT CMediaBand::_NavigateContentToDefaultURL() { TCHAR szResURL[2*MAX_URL_STRING]; // expect URL to help page and original URL HRESULT hr; LPCTSTR pszStartURL = NULL; // load inital page, this is always a local resource BOOL fSuppressOnline = SHRegGetBoolUSValue(REG_MEDIA_STR, TEXT("SuppressOnlineContent"), FALSE, FALSE); BOOL fStayOffline = SHIsGlobalOffline() || fSuppressOnline || SHRestricted2W(REST_No_MediaBarOnlineContent, NULL, 0); // ISSUE/010426/davidjen with the restriction set, // do we need a second offline page without external links, only MyMusic??????????????? if (fStayOffline) { pszStartURL = c_szOfflineURL; } else { pszStartURL = c_szLoadingURL; } hr = _BuildPageURLWithParam(pszStartURL, NULL, szResURL, ARRAYSIZE(szResURL)); if (FAILED(hr)) { StrCpyN(szResURL, c_szOfflineURL, ARRAYSIZE(szResURL)); hr = S_OK; } NavigateContentPane(szResURL); // if online, try navigating to windowsmedia.com if (!fStayOffline) { _DeferredNavigate(c_szContentUrl); } return S_OK; } HRESULT CMediaBand::_BuildPageURLWithParam(LPCTSTR pszURL, LPCTSTR pszParam, OUT LPTSTR pszBuffer, UINT uiBufSize) { USES_CONVERSION; // build a string of the form: "res://d:\winnt\system32\browselc.dll\helppage.htm#http://www.windowsmedia.com/xyz.html" HRESULT hr = S_OK; ASSERT(pszBuffer); hr = MLBuildResURLWrap(TEXT("browselc.dll"), HINST_THISDLL, ML_CROSSCODEPAGE, T2W((LPTSTR)pszURL), pszBuffer, uiBufSize, TEXT("browseui.dll")); if (SUCCEEDED(hr) && pszParam && (lstrlen(pszParam) > 0)) { StrCatBuff(pszBuffer, TEXT("#"), uiBufSize); StrCatBuff(pszBuffer, pszParam, uiBufSize); } return hr; } BOOL CMediaBand::_DeferredNavigate(LPCTSTR pszURL) { ASSERT(_strDeferredURL.Length() == 0); _strDeferredURL = pszURL; return PostMessage(_hwnd, WM_MB_DEFERRED_NAVIGATE, 0, (LPARAM) _hwnd); }