windows-nt/Source/XPSP1/NT/shell/browseui/player.cpp
2020-09-26 16:20:57 +08:00

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 = &params;
}
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,
&params, pvarResult, NULL, NULL);
if (FAILED(hr))
{
goto done;
}
done:
return hr;
}