//==========================================================================; // // Copyright (c) Microsoft Corporation 1998-2000. // //--------------------------------------------------------------------------; // // vidprot.cpp : Implementation of CTVProt // #include "stdafx.h" #ifndef TUNING_MODEL_ONLY #include #include #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(_wcstoui64(pb, NULL, RADIX_BASE_10))); // urlmon already did an addref #else swscanf(pb, L"%I64d", &pbindctx.p); #endif #else pbindctx.Attach(reinterpret_cast(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(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