4439 lines
129 KiB
C++
4439 lines
129 KiB
C++
#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);
|
|
}
|
|
|