windows-nt/Source/XPSP1/NT/shell/browseui/mediaband.cpp

4439 lines
129 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include "priv.h"
#include "sccls.h"
#include "resource.h"
#include "dhuihand.h"
#include <varutil.h>
#include "mstimeid.h"
#include <mluisupp.h>
#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<IUnknown> 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<CMediaBand *>(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<long>(_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<IBandSite, &IID_IBandSite> 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<IMediaBehaviorContentProxy, &IID_IMediaBehaviorContentProxy> 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<IMediaBehaviorContentProxy, &IID_IMediaBehaviorContentProxy> 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<IMediaBehaviorContentProxy, &IID_IMediaBehaviorContentProxy> 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<float>(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<ITIMEMediaElement> 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<CMediaBand *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
if (msg==WM_CREATE)
{
SetWindowLongPtr(hWnd, GWLP_USERDATA, (reinterpret_cast<LONG_PTR>((reinterpret_cast<CREATESTRUCT *>(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<CMediaBand *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
switch (msg)
{
case WM_ERASEBKGND:
break;
case WM_CREATE:
SetWindowLongPtr(hWnd, GWLP_USERDATA, (reinterpret_cast<LONG_PTR>((reinterpret_cast<CREATESTRUCT *>(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);
}
INT_PTR CALLBACK CMediaBand::s_PopupDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CMediaBand* pmb = reinterpret_cast<CMediaBand *>(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<float>(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<IWebBrowser2> 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 = (WNDPROC)s_PopupDlgProc;
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<ITIMEMediaElement> 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<ITIMEMediaElement> 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)
{
StrCpy(_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<ITIMEMediaElement> spMediaElem;
CComPtr<ITIMEPlayList> 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<ITIMEPlayItem> 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<IWebBrowser2> 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<IShellUIHelper> 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; i<ARRAYSIZE(_pmw); i++)
{
if (_pmw[i] && (pnm->hwndFrom == _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; i<MW_NUMBER; i++)
{
if (ISVALIDWIDGET(_pmw[i]))
{
switch (i)
{
case MW_SEEK:
DESTROY_OBJ_WITH_HANDLE(_himlSeekBack, ImageList_Destroy);
DESTROY_OBJ_WITH_HANDLE(_himlSeekFill, ImageList_Destroy);
_himlSeekBack = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(idNormal[i]), SEEK_PART_WIDTH, 0, crMask,
IMAGE_BITMAP, LR_CREATEDIBSECTION);
_himlSeekFill = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(idAlt[i]), SEEK_PART_WIDTH, 0, crMask,
IMAGE_BITMAP, LR_CREATEDIBSECTION);
break;
case MW_OPTIONS:
{
CMediaWidgetOptions* pmwb = (CMediaWidgetOptions*)_pmw[i];
pmwb->SetDepth(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);
}