252 lines
7.9 KiB
C++
252 lines
7.9 KiB
C++
|
//==========================================================================;
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation 1998-2000.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------;
|
||
|
//
|
||
|
// vidprot.cpp : Implementation of CTVProt
|
||
|
//
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
#ifndef TUNING_MODEL_ONLY
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <shlwapi.h>
|
||
|
#include "vidprot.h"
|
||
|
#include "devices.h"
|
||
|
|
||
|
DEFINE_EXTERN_OBJECT_ENTRY(__uuidof(CTVProt), CTVProt)
|
||
|
DEFINE_EXTERN_OBJECT_ENTRY(__uuidof(CDVDProt), CDVDProt)
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CTVProt
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CTVProt -- IInternetProtocolRoot
|
||
|
STDMETHODIMP CTVProt::Start(LPCWSTR szUrl,
|
||
|
IInternetProtocolSink* pOIProtSink,
|
||
|
IInternetBindInfo* pOIBindInfo,
|
||
|
DWORD grfPI,
|
||
|
HANDLE_PTR /* dwReserved */)
|
||
|
{
|
||
|
TRACELM(TRACE_DEBUG, "CTVProt::Start()");
|
||
|
if (!pOIProtSink)
|
||
|
{
|
||
|
TRACELM(TRACE_DEBUG, "CTVProt::Start() IInternetProctocolSink * == NULL");
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
m_pSink.Release();
|
||
|
m_pSink = pOIProtSink;
|
||
|
m_pSink->ReportData(BSCF_FIRSTDATANOTIFICATION, 0, 0);
|
||
|
#if 0
|
||
|
// this bug is fixed in ie 5.5+ on whistler. if you want to run on earlier versions of ie such as 2k gold then you need this.
|
||
|
m_pSink->ReportProgress(BINDSTATUS_CONNECTING, NULL); // put binding in downloading state so it doesn't ignore our IUnknown*
|
||
|
#endif
|
||
|
|
||
|
if (!pOIBindInfo) {
|
||
|
m_pSink->ReportResult(E_NOINTERFACE, 0, 0);
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
// don't run unless we're being invoked from a safe site
|
||
|
HRESULT hr = IsSafeSite(m_pSink);
|
||
|
if (FAILED(hr)) {
|
||
|
m_pSink->ReportResult(hr, 0, 0);
|
||
|
return hr;
|
||
|
}
|
||
|
ULONG count;
|
||
|
LPOLESTR pb;
|
||
|
hr = pOIBindInfo->GetBindString(BINDSTRING_FLAG_BIND_TO_OBJECT, &pb, 1, &count);
|
||
|
if (FAILED(hr)) {
|
||
|
m_pSink->ReportResult(hr, 0, 0);
|
||
|
return hr;
|
||
|
}
|
||
|
if (wcscmp(pb, BIND_TO_OBJ_VAL)) {
|
||
|
// we must be getting a bind to storage so skip the expensive stuff and
|
||
|
// wait for the bind to object which is coming next
|
||
|
m_pSink->ReportData(BSCF_LASTDATANOTIFICATION |
|
||
|
BSCF_DATAFULLYAVAILABLE, 0, 0);
|
||
|
m_pSink->ReportResult(S_OK, 0, 0);
|
||
|
m_pSink.Release();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// and, in one of the most bizarre maneuvers i've ever seen, rather than casting,
|
||
|
// urlmon passes back the ascii value of the ibindctx pointer in the string
|
||
|
hr = pOIBindInfo->GetBindString(BINDSTRING_PTR_BIND_CONTEXT, &pb, 1, &count);
|
||
|
if (FAILED(hr)) {
|
||
|
m_pSink->ReportResult(hr, 0, 0);
|
||
|
return hr;
|
||
|
}
|
||
|
_ASSERT(count == 1);
|
||
|
|
||
|
PQBindCtx pbindctx;
|
||
|
#define RADIX_BASE_10 (10)
|
||
|
#ifdef _WIN64
|
||
|
#if 0
|
||
|
// undone: turn this back on for win64 when _wcstoxi64 get into libc.c, they're in the header
|
||
|
// but not implemented so this doesn't link
|
||
|
pbindctx.Attach(reinterpret_cast<IBindCtx*>(_wcstoui64(pb, NULL, RADIX_BASE_10))); // urlmon already did an addref
|
||
|
#else
|
||
|
swscanf(pb, L"%I64d", &pbindctx.p);
|
||
|
#endif
|
||
|
#else
|
||
|
pbindctx.Attach(reinterpret_cast<IBindCtx*>(wcstol(pb, NULL, RADIX_BASE_10))); // urlmon already did an addref
|
||
|
#endif
|
||
|
|
||
|
if (!pbindctx) {
|
||
|
m_pSink->ReportResult(E_NOINTERFACE, 0, 0);
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
TRACELM(TRACE_DEBUG, "CTVProt::Start(): creating control object");
|
||
|
PQVidCtl pCtl;
|
||
|
hr = GetVidCtl(pCtl);
|
||
|
if (FAILED(hr)) {
|
||
|
m_pSink->ReportResult(hr, 0, 0);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
hr = pbindctx->RegisterObjectParam(OLESTR("IUnknown Pointer"), pCtl);
|
||
|
if (FAILED(hr)) {
|
||
|
m_pSink->ReportResult(hr, 0, 0);
|
||
|
return hr;
|
||
|
}
|
||
|
TRACELSM(TRACE_DEBUG, (dbgDump << "BINDSTATUS_IUNKNOWNAVAILABLE(29), " << KEY_CLSID_VidCtl), "");
|
||
|
m_pSink->ReportProgress(BINDSTATUS_IUNKNOWNAVAILABLE, NULL);
|
||
|
m_pSink->ReportData(BSCF_LASTDATANOTIFICATION |
|
||
|
BSCF_DATAFULLYAVAILABLE, 0, 0);
|
||
|
m_pSink->ReportResult(S_OK, 0, 0);
|
||
|
m_pSink.Release();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CTVProt::GetCachedVidCtl(PQVidCtl &pCtl, PQWebBrowser2& pW2) {
|
||
|
// hunt for cached object
|
||
|
PQServiceProvider pSP(m_pSink);
|
||
|
if (!pSP) {
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
HRESULT hr = pSP->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (LPVOID *)&pW2);
|
||
|
if (FAILED(hr)) {
|
||
|
return hr;
|
||
|
}
|
||
|
CComVariant v;
|
||
|
CComBSTR propname(KEY_CLSID_VidCtl);
|
||
|
if (!propname) {
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
hr = pW2->GetProperty(propname, &v);
|
||
|
if (FAILED(hr)) {
|
||
|
return hr;
|
||
|
}
|
||
|
if (v.vt == VT_UNKNOWN) {
|
||
|
pCtl = v.punkVal;
|
||
|
} else if (v.vt == VT_DISPATCH) {
|
||
|
pCtl = v.pdispVal;
|
||
|
} else {
|
||
|
TRACELM(TRACE_ERROR, "CTVProt::GetCachedObject(): non-object cached w/ our key");
|
||
|
pCtl.Release();
|
||
|
// don't return error. we'll ignore this and create a new one
|
||
|
}
|
||
|
// undone: look and see if pCtl already has a site.because
|
||
|
// this means we're seeing the second tv: on this page
|
||
|
// so just get the current TR/channel from it if necessary (tv: w/ no rhs)
|
||
|
// and create a new ctl
|
||
|
return NOERROR;
|
||
|
}
|
||
|
HRESULT CTVProt::GetVidCtl(PQVidCtl &pCtl) {
|
||
|
PQWebBrowser2 pW2;
|
||
|
HRESULT hr = GetCachedVidCtl(pCtl, pW2);
|
||
|
if (FAILED(hr)) {
|
||
|
return hr;
|
||
|
}
|
||
|
if (!pCtl) {
|
||
|
// undone: long term, we want to move a bunch of this create/setup logic into factoryhelp
|
||
|
// so we can share more code with the dvd: protocol and the behavior factory
|
||
|
hr = pCtl.CoCreateInstance(CLSID_MSVidCtl, NULL, CLSCTX_INPROC_SERVER);
|
||
|
if (FAILED(hr)) {
|
||
|
return hr;
|
||
|
}
|
||
|
// cache this ctl for next time
|
||
|
if (pW2) {
|
||
|
VARIANT v;
|
||
|
v.vt = VT_UNKNOWN;
|
||
|
v.punkVal = pCtl;
|
||
|
|
||
|
CComBSTR propname(KEY_CLSID_VidCtl);
|
||
|
if (!propname) {
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
hr = pW2->PutProperty(propname, v);
|
||
|
if (FAILED(hr)) {
|
||
|
TRACELM(TRACE_ERROR, "CTVProt::Start() Can't cache ctl");
|
||
|
// ignore this error. it shouldn't ever happen and if it does then it will
|
||
|
// just cause a perf degradation. trace it and move on
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// undone: parse rhs of url and create the right tuning request
|
||
|
CComVariant pTR(CFactoryHelper::GetDefaultTR());
|
||
|
if (!pTR) {
|
||
|
TRACELM(TRACE_ERROR, "CTVProt::Start() Can't find default Tune Request");
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
hr = pCtl->View(&pTR);
|
||
|
if (FAILED(hr)) {
|
||
|
TRACELM(TRACE_ERROR, "CTVProt::Start() Can't view default Tune Request");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// undone: once we know where vidctl will live in the registry then we need to put a flag
|
||
|
// in the registry just disables including any features in the tv: prot
|
||
|
|
||
|
PQFeatures pF;
|
||
|
hr = pCtl->get_FeaturesAvailable(&pF);
|
||
|
if (FAILED(hr)) {
|
||
|
TRACELM(TRACE_ERROR, "CTVProt::Start() Can't get features collection");
|
||
|
return hr;
|
||
|
}
|
||
|
// undone: look up default feature segments for tv: in registry
|
||
|
// for now we're just going to hard code the ones we want
|
||
|
|
||
|
CFeatures* pC = static_cast<CFeatures *>(pF.p);
|
||
|
CFeatures* pNewColl = new CFeatures;
|
||
|
if (!pNewColl) {
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
for (DeviceCollection::iterator i = pC->m_Devices.begin(); i != pC->m_Devices.end(); ++i) {
|
||
|
PQFeature f(*i);
|
||
|
GUID2 clsid;
|
||
|
hr = f->get__ClassID(&clsid);
|
||
|
if (FAILED(hr)) {
|
||
|
TRACELM(TRACE_ERROR, "CTVProt::GetVidCtl() Can't get feature class id");
|
||
|
continue;
|
||
|
}
|
||
|
if (clsid == CLSID_MSVidClosedCaptioning ||
|
||
|
clsid == CLSID_MSVidDataServices) {
|
||
|
pNewColl->m_Devices.push_back(*i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hr = pCtl->put_FeaturesActive(pNewColl);
|
||
|
if (FAILED(hr)) {
|
||
|
TRACELM(TRACE_ERROR, "CTVProt::Start() Can't put features collection");
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
ASSERT(pCtl);
|
||
|
hr = pCtl->Run();
|
||
|
if (FAILED(hr)) {
|
||
|
TRACELSM(TRACE_ERROR, (dbgDump << "CTVProt::Start() run failed. hr = " << hexdump(hr)), "");
|
||
|
return hr;
|
||
|
}
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif // TUNING_MODEL_ONLY
|
||
|
// end of file vidprot.cpp
|