1980 lines
47 KiB
C++
1980 lines
47 KiB
C++
// MediaBarPlayer.cpp
|
|
|
|
#include "priv.h"
|
|
|
|
#include "dispex.h"
|
|
#include "player.h"
|
|
#include "resource.h"
|
|
#include "math.h"
|
|
#include "mediautil.h"
|
|
#include "mbBehave.h"
|
|
|
|
|
|
#define WZ_PLAY L"beginElement"
|
|
#define WZ_STOP L"endElement"
|
|
#define WZ_PAUSE L"pauseElement"
|
|
#define WZ_RESUME L"resumeElement"
|
|
#define WZ_URL L"src"
|
|
#define WZ_VOLUME L"volume"
|
|
#define WZ_MUTE L"mute"
|
|
#define WZ_REGISTERED_TIME_NAME L"HTMLTIME"
|
|
#define WZ_BODY L"body"
|
|
#define WZ_PLAYER L"player"
|
|
#define WZ_ONMEDIACOMPLETE L"onmediacomplete"
|
|
#define WZ_MEDIACOMPLETE L"mediacomplete"
|
|
#define WZ_ONMEDIAERROR L"onmediaerror"
|
|
#define WZ_MEDIAERROR L"mediaerror"
|
|
#define WZ_ONTRACKCHANGE L"ontrackchange"
|
|
#define WZ_TRACKCHANGE L"trackchange"
|
|
#define WZ_ONEND L"onend"
|
|
#define WZ_END L"end"
|
|
#define WZ_PARAM L"Param"
|
|
|
|
/////////////////////// Convenience macros ////////////////////
|
|
//
|
|
// used in QI calls,
|
|
// e.g. IOleSite * pSite; p->QI( IID_TO_PPV(IOleInPlaceSite, &pSite) )
|
|
// would cause a C2440 as _src is not really a _type **.
|
|
// Note: the riid must be the _type prepended by IID_.
|
|
//
|
|
#define IID_TO_PPV(_type,_src) IID_##_type, \
|
|
reinterpret_cast<void **>(static_cast<_type **>(_src))
|
|
// Explicit directive to ignore a return value
|
|
#define IGNORE_RETURN(_call) static_cast<void>((_call))
|
|
#define ERROREXIT(hr) if(FAILED(hr)){hr = E_FAIL; goto done;}
|
|
#define IGNORE_HR(hr) IGNORE_RETURN(hr)
|
|
#define TIME_INFINITE HUGE_VAL
|
|
|
|
static inline double
|
|
Clamp(double min, double val, double max)
|
|
{
|
|
if (val < min)
|
|
{
|
|
val = min;
|
|
}
|
|
else if (val > max)
|
|
{
|
|
val = max;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
|
|
/****************************************************\
|
|
FUNCTION: CMediaBarPlayer_CreateInstance
|
|
|
|
DESCRIPTION:
|
|
This function will create an instance of the
|
|
MediaBarPlayer COM object.
|
|
\****************************************************/
|
|
HRESULT CMediaBarPlayer_CreateInstance(REFIID riid, void ** ppvObj)
|
|
{
|
|
// aggregation checking is handled in class factory
|
|
|
|
CComObject<CMediaBarPlayer> * pMediaBarPlayer = NULL;
|
|
|
|
*ppvObj = NULL;
|
|
|
|
HRESULT hr = CComObject<CMediaBarPlayer>::CreateInstance(&pMediaBarPlayer);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = pMediaBarPlayer->QueryInterface(riid, ppvObj);
|
|
if (FAILED(hr))
|
|
delete pMediaBarPlayer;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Constructor
|
|
//--------------------------------------------------------------------------
|
|
CMediaBarPlayer::CMediaBarPlayer() :
|
|
_dwDocumentEventConPtCookie(0),
|
|
_dwCookiePropNotify(0),
|
|
_pMediaBar(NULL),
|
|
_hwnd(NULL)
|
|
{
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Destructor
|
|
//--------------------------------------------------------------------------
|
|
CMediaBarPlayer::~CMediaBarPlayer()
|
|
{
|
|
_DestroyHost();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Creates the control host
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_CreateHost(HWND hWnd)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (_spBrowser.p)
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
if (hWnd && ::IsWindow(hWnd) && _pMediaBar)
|
|
{
|
|
// Register the OCHost window class
|
|
SHDRC shdrc = {sizeof(SHDRC), SHDRCF_OCHOST};
|
|
shdrc.cbSize = sizeof (SHDRC);
|
|
shdrc.dwFlags |= SHDRCF_OCHOST;
|
|
if (DllRegisterWindowClasses(&shdrc))
|
|
{
|
|
// Create an OCHost window
|
|
_hwnd = CreateWindow(OCHOST_CLASS, NULL,
|
|
(WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS) & ~(WS_HSCROLL|WS_VSCROLL),
|
|
0, 0, 0, 0,
|
|
hWnd, NULL, HINST_THISDLL, NULL);
|
|
|
|
if (_hwnd)
|
|
{
|
|
OCHINITSTRUCT ocs;
|
|
ocs.cbSize = SIZEOF(OCHINITSTRUCT);
|
|
ocs.clsidOC = CLSID_WebBrowser;
|
|
ocs.punkOwner = SAFECAST(_pMediaBar, IUnknown*);
|
|
|
|
hr = OCHost_InitOC(_hwnd, (LPARAM)&ocs);
|
|
ERROREXIT(hr)
|
|
|
|
OCHost_QueryInterface(_hwnd, IID_PPV_ARG(IWebBrowser2, &_spBrowser));
|
|
OCHost_DoVerb(_hwnd, OLEIVERB_INPLACEACTIVATE, FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!_spBrowser.p)
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
// navigate to the page containing the player
|
|
{
|
|
TCHAR szModule[_MAX_PATH];
|
|
GetModuleFileName(_Module.GetModuleInstance(), szModule, _MAX_PATH);
|
|
|
|
// generate the url for the HTML resource containing the player
|
|
CComBSTR sbstrURL(OLESTR("res://"));
|
|
sbstrURL.Append(szModule);
|
|
sbstrURL.Append(OLESTR("/"));
|
|
TCHAR szResID[11];
|
|
wnsprintf(szResID, _MAX_PATH, _T("%d"), IDH_PLAYER);
|
|
sbstrURL.Append(szResID);
|
|
|
|
hr = _Navigate(sbstrURL.m_str);
|
|
ERROREXIT(hr)
|
|
}
|
|
|
|
// listen to events
|
|
hr = _InitEventSink();
|
|
ERROREXIT(hr)
|
|
|
|
hr = S_OK;
|
|
done:
|
|
if (FAILED(hr))
|
|
{
|
|
_DestroyHost();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_Navigate(BSTR bstrUrl)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComVariant svarEmpty;
|
|
|
|
if (!bstrUrl || !_spBrowser.p)
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
hr = _spBrowser->Navigate(bstrUrl, &svarEmpty, &svarEmpty, &svarEmpty, &svarEmpty);
|
|
ERROREXIT(hr)
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Destroys the control host
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_DestroyHost()
|
|
{
|
|
_AttachPlayerEvents(FALSE);
|
|
|
|
_UnhookPropNotifies();
|
|
|
|
_DeInitEventSink();
|
|
|
|
if (_spMediaElem.p)
|
|
{
|
|
_spMediaElem.Release();
|
|
}
|
|
|
|
if (_spMediaElem2.p)
|
|
{
|
|
_spMediaElem2.Release();
|
|
}
|
|
|
|
if (_spPlayerHTMLElem2.p)
|
|
{
|
|
_spPlayerHTMLElem2.Release();
|
|
}
|
|
|
|
if (_spBodyElem.p)
|
|
{
|
|
_spBodyElem.Release();
|
|
}
|
|
|
|
if (_spBrowser.p)
|
|
{
|
|
_spBrowser.Release();
|
|
}
|
|
|
|
if (_hwnd && ::IsWindow(_hwnd))
|
|
{
|
|
::DestroyWindow(_hwnd);
|
|
_hwnd = NULL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::GetVideoHwnd(HWND * pHwnd)
|
|
{
|
|
if (pHwnd)
|
|
*pHwnd = _hwnd;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const PWSTR ppszInterestingEvents[] =
|
|
{
|
|
WZ_ONMEDIACOMPLETE,
|
|
WZ_ONMEDIAERROR,
|
|
WZ_ONEND,
|
|
WZ_ONTRACKCHANGE
|
|
};
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Attaches to player events
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_AttachPlayerEvents(BOOL fAttach)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
CComPtr<IDispatchEx> spDispEx;
|
|
CComPtr<IHTMLElement2> spElem2;
|
|
|
|
hr = _GetElementDispatch(WZ_PLAYER, &spDispEx);
|
|
ERROREXIT(hr)
|
|
|
|
hr = spDispEx->QueryInterface(IID_TO_PPV(IHTMLElement2, &spElem2));
|
|
ERROREXIT(hr)
|
|
|
|
hr = S_OK;
|
|
for (DWORD i = 0; i < ARRAYSIZE(ppszInterestingEvents); i++)
|
|
{
|
|
if (fAttach)
|
|
{
|
|
VARIANT_BOOL bSuccess = FALSE;
|
|
// Try to attach all events. We don't care if they fail
|
|
if (FAILED(spElem2->attachEvent(ppszInterestingEvents[i], static_cast<IDispatch*>(this), &bSuccess)))
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Try to detact all events. We don't care if they fail
|
|
hr = spElem2->detachEvent(ppszInterestingEvents[i], static_cast<IDispatch*>(this));
|
|
}
|
|
}
|
|
|
|
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Hooks property change notifications
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_HookPropNotifies()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComPtr<ITIMEState> spTimeState;
|
|
CComPtr<IConnectionPointContainer> spConPtCont;
|
|
|
|
if (!_spMediaElem || _spPropNotifyCP.p || _dwCookiePropNotify)
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
hr = _spMediaElem->get_currTimeState(&spTimeState);
|
|
ERROREXIT(hr)
|
|
|
|
hr = spTimeState->QueryInterface(IID_TO_PPV(IConnectionPointContainer, &spConPtCont));
|
|
ERROREXIT(hr)
|
|
|
|
hr = spConPtCont->FindConnectionPoint(IID_IPropertyNotifySink, &_spPropNotifyCP);
|
|
ERROREXIT(hr)
|
|
|
|
hr = _spPropNotifyCP->Advise(static_cast<IUnknown*>(static_cast<IDispatch*>(this)), &_dwCookiePropNotify);
|
|
ERROREXIT(hr)
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Unhooks property change notifications
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_UnhookPropNotifies()
|
|
{
|
|
if (_spPropNotifyCP.p)
|
|
{
|
|
if (_dwCookiePropNotify != 0)
|
|
{
|
|
IGNORE_HR(_spPropNotifyCP->Unadvise(_dwCookiePropNotify));
|
|
}
|
|
_spPropNotifyCP.Release();
|
|
}
|
|
_dwCookiePropNotify = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Invokes a method on the given element
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_InvokeDocument(LPWSTR pstrElem, INVOKETYPE it, LPWSTR pstrName, VARIANT * pvarArg)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
|
|
CComPtr<IDispatchEx> spDispEx;
|
|
CComBSTR sbstrName;
|
|
DISPID dispid = 0;
|
|
DISPID dispidProp = 0;
|
|
|
|
sbstrName.m_str = SysAllocString(pstrName);
|
|
if (!sbstrName.m_str)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto done;
|
|
}
|
|
|
|
hr = _GetElementDispatch(pstrElem, &spDispEx);
|
|
ERROREXIT(hr)
|
|
|
|
hr = spDispEx->GetDispID(sbstrName, fdexNameEnsure, &dispid);
|
|
ERROREXIT(hr)
|
|
|
|
switch (it)
|
|
{
|
|
case IT_METHOD:
|
|
{
|
|
dispparams.rgvarg = pvarArg;
|
|
dispparams.cArgs = (pvarArg ? 1 : 0);
|
|
|
|
hr = spDispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
|
|
ERROREXIT(hr)
|
|
}
|
|
break;
|
|
|
|
case IT_PUT:
|
|
{
|
|
dispidProp = DISPID_PROPERTYPUT;
|
|
|
|
if (!pvarArg)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
dispparams.rgvarg = pvarArg;
|
|
dispparams.rgdispidNamedArgs = &dispidProp;
|
|
dispparams.cArgs = 1;
|
|
dispparams.cNamedArgs = 1;
|
|
|
|
hr = spDispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
|
|
ERROREXIT(hr)
|
|
}
|
|
break;
|
|
|
|
case IT_GET:
|
|
{
|
|
if (!pvarArg)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
hr = spDispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispparams, pvarArg, NULL, NULL);
|
|
ERROREXIT(hr)
|
|
}
|
|
break;
|
|
}
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Gets the dispatch ptr of the document
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_GetDocumentDispatch(IDispatch ** ppDocDisp)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (!ppDocDisp)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
if (!_spBrowser)
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
hr = _spBrowser->get_Document(ppDocDisp);
|
|
ERROREXIT(hr)
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Gets the ITIMEBodyElement interface
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_GetBodyElement(ITIMEBodyElement ** ppBodyElem)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComVariant svarArg;
|
|
|
|
if (!ppBodyElem)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
hr = _InvokeDocument(WZ_BODY, IT_GET, WZ_REGISTERED_TIME_NAME, &svarArg);
|
|
ERROREXIT(hr)
|
|
|
|
hr = ::VariantChangeType(&svarArg, &svarArg, NULL, VT_DISPATCH);
|
|
ERROREXIT(hr)
|
|
|
|
if (NULL == V_DISPATCH(&svarArg))
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
hr = V_DISPATCH(&svarArg)->QueryInterface(IID_TO_PPV(ITIMEBodyElement, ppBodyElem));
|
|
ERROREXIT(hr)
|
|
|
|
ASSERT(ppBodyElem);
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Gets the ITIMEMediaElement interface
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_GetMediaElement(ITIMEMediaElement ** ppMediaElem)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComVariant svarArg;
|
|
|
|
if (!ppMediaElem)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
hr = _InvokeDocument(WZ_PLAYER, IT_GET, WZ_REGISTERED_TIME_NAME, &svarArg);
|
|
ERROREXIT(hr)
|
|
|
|
hr = ::VariantChangeType(&svarArg, &svarArg, NULL, VT_DISPATCH);
|
|
ERROREXIT(hr)
|
|
|
|
if (NULL == V_DISPATCH(&svarArg))
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
hr = V_DISPATCH(&svarArg)->QueryInterface(IID_TO_PPV(ITIMEMediaElement, ppMediaElem));
|
|
ERROREXIT(hr)
|
|
|
|
ASSERT(ppMediaElem);
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Gets the IDispatchEx pointer of the named element
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_GetElementDispatch(LPWSTR pstrElem, IDispatchEx ** ppDispEx)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComPtr<IDispatch> spElemDisp;
|
|
CComPtr<IDispatch> spDocDisp;
|
|
CComPtr<IHTMLDocument2> spDoc2;
|
|
CComPtr<IHTMLElementCollection> spAll;
|
|
CComVariant svarName;
|
|
CComVariant svarIndex;
|
|
|
|
if (!ppDispEx || !pstrElem)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
V_VT(&svarName) = VT_BSTR;
|
|
V_BSTR(&svarName) = SysAllocString(pstrElem);
|
|
|
|
if (NULL == V_BSTR(&svarName))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto done;
|
|
}
|
|
|
|
V_VT(&svarIndex) = VT_I4;
|
|
V_I4(&svarIndex) = 0;
|
|
|
|
hr = _GetDocumentDispatch(&spDocDisp);
|
|
ERROREXIT(hr)
|
|
|
|
// WebOC returns S_OK even if doc disp is not available
|
|
if (!spDocDisp.p)
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
hr = spDocDisp->QueryInterface(IID_TO_PPV(IHTMLDocument2, &spDoc2));
|
|
ERROREXIT(hr)
|
|
|
|
hr = spDoc2->get_all(&spAll);
|
|
ERROREXIT(hr)
|
|
|
|
hr = spAll->item(svarName, svarIndex, &spElemDisp);
|
|
ERROREXIT(hr)
|
|
|
|
if (spElemDisp.p)
|
|
{
|
|
hr = spElemDisp->QueryInterface(IID_TO_PPV(IDispatchEx, ppDispEx));
|
|
ERROREXIT(hr)
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Stuff to be done when document is loaded
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_OnDocumentComplete()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// store off a pointer to the media element behavior
|
|
hr = _GetMediaElement(&_spMediaElem);
|
|
ERROREXIT(hr)
|
|
|
|
hr = _spMediaElem->QueryInterface(IID_TO_PPV(ITIMEMediaElement2, &_spMediaElem2));
|
|
ERROREXIT(hr)
|
|
|
|
// store off a pointer to the player's HTML element
|
|
{
|
|
CComPtr<IDispatchEx> spPlayerDisp;
|
|
|
|
hr = _GetElementDispatch(WZ_PLAYER, &spPlayerDisp);
|
|
ERROREXIT(hr)
|
|
|
|
if (!spPlayerDisp.p)
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
hr = spPlayerDisp->QueryInterface(IID_TO_PPV(IHTMLElement2, &_spPlayerHTMLElem2));
|
|
ERROREXIT(hr)
|
|
}
|
|
|
|
// store off a pointer to the body element
|
|
hr = _GetBodyElement(&_spBodyElem);
|
|
ERROREXIT(hr)
|
|
|
|
// Attach to player events
|
|
hr = _AttachPlayerEvents(TRUE);
|
|
ERROREXIT(hr)
|
|
|
|
// Hook Property notifications
|
|
hr = _HookPropNotifies();
|
|
ERROREXIT(hr)
|
|
|
|
// set the type if deferred
|
|
if (_sbstrType.m_str)
|
|
{
|
|
hr = put_type(_sbstrType);
|
|
_sbstrType.Empty();
|
|
ERROREXIT(hr)
|
|
}
|
|
|
|
// set the url if deferred
|
|
if (_sbstrUrl.m_str)
|
|
{
|
|
hr = put_url(_sbstrUrl);
|
|
_sbstrUrl.Empty();
|
|
ERROREXIT(hr)
|
|
}
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Stuff to be done when Media is ready
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_OnMediaComplete()
|
|
{
|
|
// notify the media bar
|
|
if (_pMediaBar)
|
|
{
|
|
_pMediaBar->Notify(MEDIACOMPLETE);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Stuff to be done when Media is ready
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_OnTrackChange()
|
|
{
|
|
// notify the media bar
|
|
if (_pMediaBar)
|
|
{
|
|
_pMediaBar->Notify(TRACK_CHANGE);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Stuff to be done when track is finished
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_OnEnd()
|
|
{
|
|
// notify the media bar
|
|
if (_pMediaBar)
|
|
{
|
|
_pMediaBar->Notify(MEDIA_TRACK_FINISHED);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// notification that there was some error playing the Media stream
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_OnMediaError(int iErrCode)
|
|
{
|
|
CComPtr<IDispatch> spWMP;
|
|
if (_spMediaElem && SUCCEEDED(_spMediaElem->get_playerObject(&spWMP)))
|
|
{
|
|
VARIANT varError;
|
|
if (SUCCEEDED(GetProp(spWMP, L"error", &varError)))
|
|
{
|
|
CallMethod(varError.pdispVal, L"webHelp");
|
|
}
|
|
VariantClear(&varError);
|
|
}
|
|
// notify the media bar
|
|
if (_pMediaBar)
|
|
{
|
|
_pMediaBar->OnMediaError(iErrCode);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Handle property change notifications
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::OnChanged(DISPID dispid)
|
|
{
|
|
// notify the media bar
|
|
if (_pMediaBar)
|
|
{
|
|
_pMediaBar->Notify(dispid);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IMediaBarPlayer
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Init the player
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::Init(HWND hWnd, IMediaBar * pMediaBar)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (!pMediaBar)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
// store a weak ref to prevent circular reference
|
|
_pMediaBar = pMediaBar;
|
|
|
|
hr = _CreateHost(hWnd);
|
|
ERROREXIT(hr)
|
|
|
|
hr = S_OK;
|
|
done:
|
|
if (FAILED(hr))
|
|
{
|
|
DeInit();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// DeInit the player
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::DeInit()
|
|
{
|
|
_pMediaBar = NULL;
|
|
|
|
return _DestroyHost();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// sets the media clip type
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::put_type(BSTR bstrType)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComVariant svarArg;
|
|
CComVariant svarEmpty;
|
|
|
|
svarArg.vt = VT_NULL;
|
|
svarEmpty.vt = VT_NULL;
|
|
|
|
if (!IsReady())
|
|
{
|
|
_sbstrType.m_str = ::SysAllocString(bstrType);
|
|
if (bstrType && !_sbstrType)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
goto done;
|
|
}
|
|
|
|
if (bstrType)
|
|
{
|
|
V_VT(&svarArg) = VT_BSTR;
|
|
V_BSTR(&svarArg) = SysAllocString(bstrType);
|
|
if (NULL == V_BSTR(&svarArg))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
// always stop the player
|
|
hr = _spMediaElem->endElement();
|
|
ERROREXIT(hr)
|
|
|
|
hr = _spMediaElem->put_src(svarEmpty);
|
|
ERROREXIT(hr)
|
|
|
|
hr = _spMediaElem->put_type(svarArg);
|
|
ERROREXIT(hr)
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// sets the media clip url
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::put_url(BSTR bstrUrl)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComVariant svarArg;
|
|
CComVariant svarEmpty;
|
|
|
|
svarArg.vt = VT_NULL;
|
|
svarEmpty.vt = VT_NULL;
|
|
|
|
if (!IsReady())
|
|
{
|
|
_sbstrUrl.m_str = ::SysAllocString(bstrUrl);
|
|
if (bstrUrl && !_sbstrUrl)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
goto done;
|
|
}
|
|
|
|
if (bstrUrl)
|
|
{
|
|
V_VT(&svarArg) = VT_BSTR;
|
|
V_BSTR(&svarArg) = SysAllocString(bstrUrl);
|
|
if (NULL == V_BSTR(&svarArg))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
// always stop the player
|
|
hr = _spMediaElem->endElement();
|
|
ERROREXIT(hr)
|
|
|
|
hr = _spMediaElem->put_src(svarArg);
|
|
ERROREXIT(hr)
|
|
|
|
// always start the player
|
|
hr = _spMediaElem->beginElement();
|
|
ERROREXIT(hr)
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// gets the media clip url
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::get_url(BSTR * pbstrUrl)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComVariant svarArg;
|
|
|
|
if (!pbstrUrl || !IsReady())
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
*pbstrUrl = NULL;
|
|
|
|
hr = _spMediaElem->get_src(&svarArg);
|
|
ERROREXIT(hr)
|
|
|
|
hr = svarArg.ChangeType(VT_BSTR);
|
|
ERROREXIT(hr)
|
|
|
|
if (svarArg.bstrVal)
|
|
{
|
|
*pbstrUrl = SysAllocString(svarArg.bstrVal);
|
|
if (NULL == *pbstrUrl)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// gets the player attribute
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::get_player(BSTR * pbstrPlayer)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComVariant svarArg;
|
|
|
|
if (!pbstrPlayer || !IsReady())
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
*pbstrPlayer = NULL;
|
|
|
|
hr = _spMediaElem->get_player(&svarArg);
|
|
ERROREXIT(hr)
|
|
|
|
hr = svarArg.ChangeType(VT_BSTR);
|
|
ERROREXIT(hr)
|
|
|
|
if (svarArg.bstrVal)
|
|
{
|
|
*pbstrPlayer = SysAllocString(svarArg.bstrVal);
|
|
if (NULL == *pbstrPlayer)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// sets the volume
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::put_volume(double dblVolume)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComVariant svarArg;
|
|
|
|
if (!IsReady())
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
V_VT(&svarArg) = VT_R8;
|
|
V_R8(&svarArg) = dblVolume;
|
|
|
|
hr = _spMediaElem->put_volume(svarArg);
|
|
ERROREXIT(hr)
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// gets the volume
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::get_volume(double * pdblVolume)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// gets the media element pointer
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::get_mediaElement(ITIMEMediaElement ** ppMediaElem)
|
|
{
|
|
if (!ppMediaElem || !_spMediaElem)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
*ppMediaElem = _spMediaElem;
|
|
(_spMediaElem.p)->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// sets the mute
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::put_mute(BOOL bMute)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComVariant svarArg;
|
|
|
|
if (!IsReady())
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
V_VT(&svarArg) = VT_BOOL;
|
|
V_BOOL(&svarArg) = bMute ? VARIANT_TRUE : VARIANT_FALSE;
|
|
|
|
hr = _spMediaElem->put_mute(svarArg);
|
|
ERROREXIT(hr)
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// gets the mute
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::get_mute(BOOL * pbMute)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// plays the media
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::Play()
|
|
{
|
|
if (!IsReady())
|
|
return E_FAIL;
|
|
|
|
return _spMediaElem->beginElement();
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// stops the media
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::Stop()
|
|
{
|
|
if (!IsReady())
|
|
return E_FAIL;
|
|
|
|
return _spMediaElem->endElement();
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// pauses the media
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::Pause()
|
|
{
|
|
if (!IsReady())
|
|
return E_FAIL;
|
|
|
|
return _spMediaElem->pauseElement();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// resumes the media
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::Resume()
|
|
{
|
|
if (!IsReady())
|
|
return E_FAIL;
|
|
|
|
return _spMediaElem->resumeElement();
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// seeks the media to the given progress
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::Seek(double dblProgress)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComPtr<ITIMEState> spTimeState;
|
|
double dblActiveDur = 0.0;
|
|
double dblSeekTime = 0.0;
|
|
VARIANT_BOOL vbActive = VARIANT_FALSE;
|
|
|
|
if (!IsReady())
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
if (!IsPlayList())
|
|
{
|
|
hr = _spMediaElem->get_currTimeState(&spTimeState);
|
|
ERROREXIT(hr)
|
|
|
|
hr = spTimeState->get_activeDur(&dblActiveDur);
|
|
ERROREXIT(hr)
|
|
|
|
hr = spTimeState->get_isActive(&vbActive);
|
|
ERROREXIT(hr)
|
|
|
|
// ISSUE: workaround for IE6 #20622
|
|
// if the clip has ended, reactivate it in the paused state
|
|
if (VARIANT_FALSE == vbActive)
|
|
{
|
|
_spMediaElem->beginElement();
|
|
_spMediaElem->pauseElement();
|
|
}
|
|
|
|
if (TIME_INFINITE == dblActiveDur)
|
|
{
|
|
// we shouldn't be allowed to seek
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
Clamp(0.0, dblProgress, 1.0);
|
|
dblSeekTime = dblActiveDur * dblProgress;
|
|
}
|
|
|
|
// seek the body
|
|
hr = _spMediaElem->seekActiveTime(dblSeekTime);
|
|
ERROREXIT(hr)
|
|
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
CComPtr<ITIMEPlayList> spPlayList;
|
|
CComPtr<ITIMEPlayItem> spPlayItem;
|
|
CComPtr<ITIMEMediaNative> spMediaNative;
|
|
|
|
hr = _spMediaElem->get_playList(&spPlayList);
|
|
if (SUCCEEDED(hr) && spPlayList)
|
|
{
|
|
hr = spPlayList->get_activeTrack(&spPlayItem);
|
|
if (SUCCEEDED(hr) && spPlayItem)
|
|
{
|
|
spPlayItem->get_dur(&dblActiveDur);
|
|
dblSeekTime = dblActiveDur * dblProgress;
|
|
|
|
hr = _spMediaElem->QueryInterface(IID_TO_PPV(ITIMEMediaNative, &spMediaNative));
|
|
if (SUCCEEDED(hr) && spMediaNative)
|
|
{
|
|
spMediaNative->seekActiveTrack(dblSeekTime);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Resize the video to fit in the given window size, preserving aspect ratio
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::Resize(LONG* plHeight, LONG* plWidth, BOOL fClampMaxSizeToNaturalSize)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
long lMediaWidth = 0;
|
|
long lMediaHeight = 0;
|
|
long lResizeWidth = 0;
|
|
long lResizeHeight = 0;
|
|
float flWndAspect = 0.0f;
|
|
float flMediaAspect = 0.0f;
|
|
|
|
if (!IsReady() || !plHeight || !plWidth || (0 == (*plHeight)) || (0 == (*plWidth)))
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
hr = _spMediaElem->get_mediaWidth(&lMediaWidth);
|
|
ERROREXIT(hr)
|
|
|
|
hr = _spMediaElem->get_mediaHeight(&lMediaHeight);
|
|
ERROREXIT(hr)
|
|
|
|
// do resize only if both dimensions are non-zero
|
|
if (0 != lMediaWidth && 0 != lMediaHeight)
|
|
{
|
|
// if natural media size <= window size and max size is clamped to natural media size
|
|
if ( fClampMaxSizeToNaturalSize
|
|
&& lMediaWidth <= (*plWidth)
|
|
&& lMediaHeight <= (*plHeight))
|
|
{
|
|
// set the media back to it's natural size
|
|
lResizeHeight = lMediaHeight;
|
|
lResizeWidth = lMediaWidth;
|
|
}
|
|
else
|
|
{
|
|
// resize the media to the window size
|
|
|
|
flWndAspect = (float) (*plHeight) / (float) (*plWidth);
|
|
flMediaAspect = (float) lMediaHeight / (float) lMediaWidth;
|
|
|
|
if (flMediaAspect <= flWndAspect)
|
|
{
|
|
// set width to window width and compute the height according to aspect ratio
|
|
lResizeWidth = (long)(*plWidth);
|
|
lResizeHeight = (long)(lResizeWidth * flMediaAspect);
|
|
}
|
|
else
|
|
{
|
|
// set height to window height and compute the width according to aspect ratio
|
|
lResizeHeight = (long)(*plHeight);
|
|
lResizeWidth = (long)(lResizeHeight / flMediaAspect);
|
|
}
|
|
}
|
|
|
|
// set the resized height and width on the HTML element
|
|
{
|
|
CComPtr<IHTMLStyle> spStyle;
|
|
CComPtr<IHTMLElement2> spHTMLElem;
|
|
|
|
hr = _spPlayerHTMLElem2->QueryInterface(IID_PPV_ARG(IHTMLElement2, &spHTMLElem));
|
|
ERROREXIT(hr)
|
|
|
|
// Using runtimeStyle instead of style.
|
|
// (Previously, we did the reverse as a work around for IE6 #20625. But now style is broken.)
|
|
hr = spHTMLElem->get_runtimeStyle(&spStyle);
|
|
ERROREXIT(hr)
|
|
|
|
hr = spStyle->put_pixelWidth(lResizeWidth);
|
|
ERROREXIT(hr)
|
|
|
|
hr = spStyle->put_pixelHeight(lResizeHeight);
|
|
ERROREXIT(hr)
|
|
}
|
|
}
|
|
|
|
*plWidth = lResizeWidth ;
|
|
*plHeight = lResizeHeight;
|
|
|
|
hr = S_OK;
|
|
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IDispatch
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Name: Invoke
|
|
//
|
|
// 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 CMediaBarPlayer::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)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
switch (dispIdMember)
|
|
{
|
|
case 0: //this is the case for events that have been hooked using attachEvent
|
|
{
|
|
CComBSTR sbstrEvent;
|
|
CComPtr <IHTMLEventObj> pEventObj;
|
|
|
|
if ((NULL != pDispParams) && (NULL != pDispParams->rgvarg) &&
|
|
(V_VT(&(pDispParams->rgvarg[0])) == VT_DISPATCH))
|
|
{
|
|
hr = THR((pDispParams->rgvarg[0].pdispVal)->QueryInterface(IID_IHTMLEventObj, (void**)&pEventObj));
|
|
if (FAILED(hr))
|
|
{
|
|
goto done;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(0 && "Unexpected dispparam values passed to CEventMgr::Invoke(dispid = 0)");
|
|
hr = E_UNEXPECTED;
|
|
goto done;
|
|
}
|
|
|
|
hr = THR(pEventObj->get_type(&sbstrEvent));
|
|
|
|
if (0 == StrCmpIW(WZ_TRACKCHANGE, sbstrEvent))
|
|
{
|
|
_OnTrackChange();
|
|
}
|
|
if (0 == StrCmpIW(WZ_MEDIACOMPLETE, sbstrEvent))
|
|
{
|
|
_OnMediaComplete();
|
|
}
|
|
else if (0 == StrCmpIW(WZ_MEDIAERROR, sbstrEvent))
|
|
{
|
|
|
|
int iErrCode = -1;
|
|
|
|
// Get the param if available
|
|
CComPtr<IHTMLEventObj2> spEventObj2;
|
|
CComVariant svarParam;
|
|
CComBSTR sbstrParam(WZ_PARAM);
|
|
|
|
hr = pEventObj->QueryInterface(IID_IHTMLEventObj2, (void**) &spEventObj2);
|
|
if (SUCCEEDED(hr) && sbstrParam.m_str)
|
|
{
|
|
// get the params
|
|
hr = spEventObj2->getAttribute(sbstrParam, 0, &svarParam);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// change type to int
|
|
hr = svarParam.ChangeType(VT_I4);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
iErrCode = V_I4(&svarParam);
|
|
}
|
|
}
|
|
}
|
|
_OnMediaError(iErrCode);
|
|
}
|
|
else if (0 == StrCmpIW(WZ_END, sbstrEvent))
|
|
{
|
|
_OnEnd();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 259: // DISPID_DOCUMENTCOMPLETE
|
|
{
|
|
hr = _OnDocumentComplete();
|
|
ERROREXIT(hr)
|
|
}
|
|
break;
|
|
}
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return S_OK;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Name: _InitEventSink
|
|
//
|
|
// Abstract:
|
|
// Finds a connection point on the HTMLDocument interface
|
|
// and passes this as an event handler.
|
|
///////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_InitEventSink()
|
|
{
|
|
// Get a connection point to the container
|
|
CComPtr<IConnectionPointContainer> spDocCPC;
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
hr = _spBrowser->QueryInterface(IID_IConnectionPointContainer, (void**)&spDocCPC);
|
|
ERROREXIT(hr)
|
|
|
|
hr = THR(spDocCPC->FindConnectionPoint(DIID_DWebBrowserEvents2, &_spDocConPt ));
|
|
ERROREXIT(hr)
|
|
|
|
hr = THR(_spDocConPt->Advise(static_cast<IUnknown*>(static_cast<DWebBrowserEvents2*>(this)), &_dwDocumentEventConPtCookie));
|
|
ERROREXIT(hr)
|
|
|
|
hr = S_OK;
|
|
done:
|
|
if (FAILED(hr))
|
|
{
|
|
_DeInitEventSink();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Name: _DeInitEventSink
|
|
//
|
|
///////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_DeInitEventSink()
|
|
{
|
|
//release the document connection points
|
|
if (_spDocConPt)
|
|
{
|
|
if (_dwDocumentEventConPtCookie != 0)
|
|
{
|
|
IGNORE_HR(_spDocConPt->Unadvise(_dwDocumentEventConPtCookie));
|
|
}
|
|
_spDocConPt.Release();
|
|
}
|
|
_dwDocumentEventConPtCookie = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
double
|
|
STDMETHODCALLTYPE
|
|
CMediaBarPlayer::GetTrackProgress()
|
|
{
|
|
if (IsReady())
|
|
{
|
|
if (!IsPlayList())
|
|
{
|
|
CComPtr<ITIMEState> spTimeState;
|
|
if (SUCCEEDED(_spMediaElem->get_currTimeState(&spTimeState)) && spTimeState)
|
|
{
|
|
double dblProgress = 0.0;
|
|
if (SUCCEEDED(spTimeState->get_progress(&dblProgress)))
|
|
{
|
|
return dblProgress;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CComPtr<ITIMEMediaNative> spMediaNative;
|
|
double dblProgress, dblActiveDur;
|
|
CComPtr<ITIMEPlayList> spPlayList;
|
|
CComPtr<ITIMEPlayItem> spPlayItem;
|
|
|
|
if (SUCCEEDED(_spMediaElem->get_playList(&spPlayList)) && spPlayList)
|
|
{
|
|
if (SUCCEEDED(spPlayList->get_activeTrack(&spPlayItem)) && spPlayItem)
|
|
{
|
|
spPlayItem->get_dur(&dblActiveDur);
|
|
if (SUCCEEDED(_spMediaElem->QueryInterface(IID_TO_PPV(ITIMEMediaNative, &spMediaNative))) && spMediaNative)
|
|
{
|
|
spMediaNative->get_activeTrackTime(&dblProgress);
|
|
return dblProgress / dblActiveDur;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
double
|
|
STDMETHODCALLTYPE
|
|
CMediaBarPlayer::GetTrackTime()
|
|
{
|
|
if (IsReady())
|
|
{
|
|
CComPtr<ITIMEState> spTimeState;
|
|
if (SUCCEEDED(_spMediaElem->get_currTimeState(&spTimeState)) && spTimeState)
|
|
{
|
|
double dblTime = 0.0;
|
|
if (SUCCEEDED(spTimeState->get_simpleTime(&dblTime)))
|
|
{
|
|
return dblTime;
|
|
}
|
|
}
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
double
|
|
STDMETHODCALLTYPE
|
|
CMediaBarPlayer::GetTrackLength()
|
|
{
|
|
if (IsReady())
|
|
{
|
|
double dblDur = 0.0;
|
|
|
|
if (SUCCEEDED(_spMediaElem->get_mediaDur(&dblDur)))
|
|
return dblDur ;
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
// Returns a progress between 0 and 100 and whether this is download or buffering progress
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::GetBufProgress(double * pdblProg, ProgressType * ppt)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
VARIANT_BOOL vb = VARIANT_FALSE;
|
|
|
|
if (!pdblProg || !ppt)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
if (!IsReady())
|
|
{
|
|
hr = E_FAIL;
|
|
goto done;
|
|
}
|
|
|
|
*pdblProg = 0.0;
|
|
*ppt = PT_None;
|
|
|
|
hr = _spMediaElem2->get_isStreamed(&vb);
|
|
if (FAILED(hr))
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
if (VARIANT_TRUE == vb)
|
|
{
|
|
CComVariant svarBufProg;
|
|
|
|
hr = _spMediaElem2->get_bufferingProgress(&svarBufProg);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppt = PT_Buffering;
|
|
if (SUCCEEDED(svarBufProg.ChangeType(VT_R8)))
|
|
{
|
|
*pdblProg = V_R8(&svarBufProg);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CComVariant svarDownloadProg;
|
|
|
|
hr = _spMediaElem2->get_downloadProgress(&svarDownloadProg);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppt = PT_Download;
|
|
if (SUCCEEDED(svarDownloadProg.ChangeType(VT_R8)))
|
|
{
|
|
*pdblProg = V_R8(&svarDownloadProg);
|
|
}
|
|
}
|
|
}
|
|
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
VARIANT_BOOL STDMETHODCALLTYPE
|
|
CMediaBarPlayer::isMuted()
|
|
{
|
|
VARIANT_BOOL vbMuted = VARIANT_FALSE;
|
|
if (IsReady())
|
|
{
|
|
CComPtr<ITIMEState> spTimeState;
|
|
if (SUCCEEDED(_spMediaElem->get_currTimeState(&spTimeState)) && spTimeState)
|
|
{
|
|
spTimeState->get_isMuted(&vbMuted);
|
|
}
|
|
}
|
|
return vbMuted;
|
|
}
|
|
|
|
VARIANT_BOOL STDMETHODCALLTYPE
|
|
CMediaBarPlayer::isPaused()
|
|
{
|
|
VARIANT_BOOL vbPaused = VARIANT_FALSE;
|
|
if (IsReady())
|
|
{
|
|
CComPtr<ITIMEState> spTimeState;
|
|
if (SUCCEEDED(_spMediaElem->get_currTimeState(&spTimeState)) && spTimeState)
|
|
{
|
|
spTimeState->get_isPaused(&vbPaused);
|
|
}
|
|
}
|
|
return vbPaused;
|
|
}
|
|
|
|
VARIANT_BOOL STDMETHODCALLTYPE
|
|
CMediaBarPlayer::isStopped()
|
|
{
|
|
VARIANT_BOOL vbActive = VARIANT_FALSE;
|
|
if (IsReady())
|
|
{
|
|
CComPtr<ITIMEState> spTimeState;
|
|
if (SUCCEEDED(_spMediaElem->get_currTimeState(&spTimeState)) && spTimeState)
|
|
{
|
|
spTimeState->get_isActive(&vbActive);
|
|
}
|
|
}
|
|
return (vbActive ? VARIANT_FALSE : VARIANT_TRUE);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::Next()
|
|
{
|
|
return _SetTrack(TT_Next);;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::Prev()
|
|
{
|
|
return _SetTrack(TT_Prev);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CMediaBarPlayer::_SetTrack(TrackType tt)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComPtr<ITIMEPlayList> spPlayList;
|
|
|
|
if (!IsReady())
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
hr = _spMediaElem->get_playList(&spPlayList);
|
|
ERROREXIT(hr)
|
|
|
|
if (NULL != spPlayList.p)
|
|
{
|
|
if (TT_Next == tt)
|
|
{
|
|
hr = spPlayList->nextTrack();
|
|
ERROREXIT(hr)
|
|
}
|
|
else if (TT_Prev == tt)
|
|
{
|
|
hr = spPlayList->prevTrack();
|
|
ERROREXIT(hr)
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
LONG_PTR
|
|
STDMETHODCALLTYPE
|
|
CMediaBarPlayer::GetPlayListItemIndex()
|
|
{
|
|
CComPtr<ITIMEPlayList> spPlayList;
|
|
long lIndex = -1;
|
|
|
|
if (IsReady())
|
|
{
|
|
if (SUCCEEDED(_spMediaElem->get_playList(&spPlayList)))
|
|
{
|
|
CComPtr<ITIMEPlayItem> spPlayItem;
|
|
if (spPlayList && SUCCEEDED(spPlayList->get_activeTrack(&spPlayItem)))
|
|
{
|
|
if (spPlayItem && SUCCEEDED(spPlayItem->get_index(&lIndex)))
|
|
return lIndex;
|
|
}
|
|
}
|
|
}
|
|
return (LONG_PTR)lIndex;
|
|
}
|
|
|
|
LONG_PTR
|
|
STDMETHODCALLTYPE
|
|
CMediaBarPlayer::GetPlayListItemCount()
|
|
{
|
|
CComPtr<ITIMEPlayList> spPlayList;
|
|
LONG lLength = 0;
|
|
|
|
if (IsReady())
|
|
{
|
|
if (SUCCEEDED(_spMediaElem->get_playList(&spPlayList)))
|
|
{
|
|
if (spPlayList && SUCCEEDED(spPlayList->get_length(&lLength)))
|
|
{
|
|
return lLength;
|
|
}
|
|
}
|
|
}
|
|
return lLength;
|
|
}
|
|
|
|
HRESULT
|
|
STDMETHODCALLTYPE
|
|
CMediaBarPlayer::SetActiveTrack( long lIndex)
|
|
{
|
|
CComPtr<ITIMEPlayList> spPlayList;
|
|
HRESULT hr = S_OK;
|
|
|
|
if (IsReady())
|
|
{
|
|
hr = _spMediaElem->get_playList(&spPlayList);
|
|
ERROREXIT(hr);
|
|
|
|
if (spPlayList)
|
|
{
|
|
VARIANT vIndex;
|
|
VariantInit(&vIndex);
|
|
|
|
vIndex.vt = VT_I4;
|
|
vIndex.lVal = lIndex;
|
|
|
|
hr = spPlayList->put_activeTrack(vIndex) ;
|
|
ERROREXIT(hr);
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
|
|
done :
|
|
return hr ;
|
|
}
|
|
|
|
BOOL
|
|
STDMETHODCALLTYPE
|
|
CMediaBarPlayer::IsPausePossible()
|
|
{
|
|
if (IsReady())
|
|
{
|
|
VARIANT_BOOL vbIsPausePossible = VARIANT_FALSE;
|
|
|
|
if (SUCCEEDED(_spMediaElem->get_canPause(&vbIsPausePossible)))
|
|
{
|
|
return (vbIsPausePossible == VARIANT_TRUE) ? TRUE : FALSE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
STDMETHODCALLTYPE
|
|
CMediaBarPlayer::IsSeekPossible()
|
|
{
|
|
if (IsReady())
|
|
{
|
|
VARIANT_BOOL vbIsSeekPossible = VARIANT_FALSE;
|
|
|
|
if (SUCCEEDED(_spMediaElem->get_canSeek(&vbIsSeekPossible)))
|
|
{
|
|
return (vbIsSeekPossible == VARIANT_TRUE) ? TRUE : FALSE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
STDMETHODCALLTYPE
|
|
CMediaBarPlayer::IsStreaming()
|
|
{
|
|
if (IsReady())
|
|
{
|
|
VARIANT_BOOL vbIsStreaming = VARIANT_FALSE;
|
|
|
|
if (SUCCEEDED(_spMediaElem2->get_isStreamed(&vbIsStreaming)))
|
|
{
|
|
return (vbIsStreaming == VARIANT_TRUE) ? TRUE : FALSE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
STDMETHODCALLTYPE
|
|
CMediaBarPlayer::IsPlayList()
|
|
{
|
|
VARIANT_BOOL vbIsPlayList = VARIANT_FALSE;
|
|
|
|
if (IsReady())
|
|
{
|
|
if (SUCCEEDED(_spMediaElem->get_hasPlayList(&vbIsPlayList)))
|
|
{
|
|
return (vbIsPlayList == VARIANT_TRUE) ? TRUE : FALSE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
STDMETHODCALLTYPE
|
|
CMediaBarPlayer::IsSkippable()
|
|
{
|
|
BOOL fRet = TRUE;
|
|
// We need to check if the client has specified CLIENTSKIP="no" and respect that. This is to prevent
|
|
// the media bar from allowing the user to skip server-side stuff, which is a no-no. There are legal restrictions
|
|
// related to this.
|
|
CComDispatchDriverEx spWMP;
|
|
if (_spMediaElem && SUCCEEDED(_spMediaElem->get_playerObject(&spWMP)) && spWMP)
|
|
{
|
|
CComVariant vtControls;
|
|
HRESULT hr = spWMP.GetPropertyByName(L"controls", &vtControls);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CComDispatchDriverEx pwmpControls;
|
|
pwmpControls = vtControls;
|
|
|
|
// We're only checking for next (but not back), and assuming that NOSKIP will affect only "next".
|
|
CComVariant vtNext = "Next";
|
|
CComVariant vtEnabled;
|
|
hr = pwmpControls.GetPropertyByName1(L"isAvailable", &vtNext, &vtEnabled);
|
|
if (SUCCEEDED(hr) && (V_VT(&vtEnabled) == VT_BOOL))
|
|
{
|
|
fRet = (V_BOOL(&vtEnabled) == VARIANT_TRUE);
|
|
}
|
|
}
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
#ifdef SINKWMP
|
|
HRESULT CMediaBarPlayer::InitWMPSink()
|
|
{
|
|
if (!_spWMP)
|
|
{
|
|
if (SUCCEEDED(_spMediaElem->get_playerObject(&_spWMP)))
|
|
{
|
|
CComPtr<IConnectionPointContainer> pcpc;
|
|
|
|
HRESULT hr = _spWmp->QueryInterface(IID_TO_PPV(IConnectionPointContainer, &pcpc));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pcpc->FindConnectionPoint(DIID__WMPOCXEvents, &_spWMPCP);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _spWMPCP->Advise(GetUnknown(), &_dwWMPCookie);
|
|
if (FAILED(hr))
|
|
{
|
|
m_pcpMediaEvents.Release();
|
|
m_dwMediaEventsCookie = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
#endif
|
|
|
|
HRESULT CMediaBarPlayer::GetProp(IDispatch* pDispatch, OLECHAR* pwzProp, VARIANT* pvarResult, DISPPARAMS* pParams)
|
|
{
|
|
DISPID dispid = NULL;
|
|
HRESULT hr = S_OK;
|
|
DISPPARAMS params = {NULL, NULL, 0, 0};
|
|
|
|
if (!pParams)
|
|
{
|
|
pParams = ¶ms;
|
|
}
|
|
|
|
if (!pDispatch)
|
|
{
|
|
hr = E_POINTER;
|
|
goto done;
|
|
}
|
|
|
|
hr = pDispatch->GetIDsOfNames(IID_NULL, &pwzProp, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
|
|
if (FAILED(hr))
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
hr = pDispatch->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET,
|
|
pParams, pvarResult, NULL, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CMediaBarPlayer::CallMethod(IDispatch* pDispatch, OLECHAR* pwzMethod, VARIANT* pvarResult, VARIANT* pvarArgument1)
|
|
{
|
|
DISPID dispid = NULL;
|
|
HRESULT hr = S_OK;
|
|
DISPPARAMS params = {pvarArgument1, NULL, 0, 0};
|
|
|
|
if (NULL != pvarArgument1)
|
|
{
|
|
params.cArgs = 1;
|
|
}
|
|
|
|
if (!pDispatch)
|
|
{
|
|
hr = E_POINTER;
|
|
goto done;
|
|
}
|
|
|
|
hr = pDispatch->GetIDsOfNames(IID_NULL, &pwzMethod, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
|
|
if (FAILED(hr))
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
hr = pDispatch->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD,
|
|
¶ms, pvarResult, NULL, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
return hr;
|
|
}
|
|
|