// Copyright (C) 1996-1997 Microsoft Corporation. All rights reserved. // contains internet helper classes CDownloadSink and CInternetControl #include "header.h" #include "Internet.H" static VARTYPE rgI4[] = { VT_I4 }; typedef enum { InternetEvent_Progress = 0, InternetEvent_ReadyStateChange = 1 } INTERNETEVENTS; static EVENTINFO rgEvents [] = { { DISPID_PROGRESS, 1, rgI4 }, // (long percentDone) { DISPID_READYSTATECHANGE, 1, rgI4 }, // (OLE_READYSTATE newState) }; // local class for doing async monitoring. It's not really all that // general purpose, but it does the job... // REVIEW: 06-Jul-1997 [ralphw] Why do we need this for HHCtrl? class CDownloadSink : public IBindStatusCallback { public: CDownloadSink(IUnknown *punkOuter,CInternetControl *,DISPID ); ~CDownloadSink(); STDMETHOD(QueryInterface)(REFIID riid, void **ppvObjOut); STDMETHOD_(ULONG, AddRef)(); STDMETHOD_(ULONG, Release)(); STDMETHOD(OnStartBinding)( /* [in] */ DWORD grfBSCOption, /* [in] */ IBinding *pib); STDMETHOD(GetPriority)( /* [out] */ LONG *pnPriority); STDMETHOD(OnLowResource)( /* [in] */ DWORD reserved); STDMETHOD(OnProgress)( /* [in] */ ULONG ulProgress, /* [in] */ ULONG ulProgressMax, /* [in] */ ULONG ulStatusCode, /* [in] */ LPCWSTR szStatusText); STDMETHOD(OnStopBinding)( /* [in] */ HRESULT hresult, /* [in] */ LPCWSTR szError); STDMETHOD(GetBindInfo)( /* [out] */ DWORD *grfBINDINFOF, /* [unique][out][in] */ BINDINFO *pbindinfo); STDMETHOD(OnDataAvailable)( /* [in] */ DWORD grfBSCF, /* [in] */ DWORD dwSize, /* [in] */ FORMATETC *pformatetc, /* [in] */ STGMEDIUM *pstgmed); STDMETHOD(OnObjectAvailable)( /* [in] */ REFIID riid, /* [iid_is][in] */ IUnknown *punk); CDownloadSink * Next() { return(m_next); } void Next(CDownloadSink *n) { m_next = n; } DISPID DispId() { return(m_propId); } IBinding * Binding() { return(m_binding); } private: CDownloadSink * m_next; CInternetControl * m_control; DISPID m_propId; IBinding * m_binding; DWORD m_ref; IStream * m_stream; }; CDownloadSink::CDownloadSink(IUnknown * punkOuter, CInternetControl * control, DISPID propId) { m_control = control; m_control->AddRef(); m_propId = propId; m_next = 0; m_binding = 0; m_ref = 0; m_stream = 0; DBWIN("CDownloadSink created."); } CDownloadSink::~CDownloadSink() { if (m_control) m_control->Release(); if (m_binding) m_binding->Release(); if (m_stream) m_stream->Release(); } STDMETHODIMP CDownloadSink::QueryInterface(const GUID &iid, void **ppv) { if (IsEqualGUID(iid, IID_IUnknown) || IsEqualGUID(iid, IID_IBindStatusCallback)) { *ppv = this; AddRef(); return(NOERROR); } return(E_NOINTERFACE); } STDMETHODIMP_(ULONG) CDownloadSink::AddRef() { return(++m_ref); } STDMETHODIMP_(ULONG) CDownloadSink::Release() { if (!--m_ref) { delete this; return(0); } return(m_ref); } STDMETHODIMP CDownloadSink::GetBindInfo(DWORD *grfBINDF, BINDINFO *pbindInfo) { *grfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_NOCOPYDATA; return(NOERROR); } STDMETHODIMP CDownloadSink::OnStartBinding(DWORD /*grfBSCOption*/, IBinding *pib) { // BUGBUG: should check to see options are what we think they are m_binding = pib; pib->AddRef(); return(NOERROR); } STDMETHODIMP CDownloadSink::GetPriority( LONG *pnPriority) { return(E_NOTIMPL); } STDMETHODIMP CDownloadSink::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR pwzStatusText) { return m_control->OnProgress(m_propId,ulProgress, ulProgressMax, ulStatusCode, pwzStatusText); } STDMETHODIMP CDownloadSink::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC * pFmtetc, STGMEDIUM * pstgmed) { #ifdef DEBUG char msg[200]; wsprintf(msg,"::OnDataAvailable(%0xd,%d,%s,%s)", grfBSCF, dwSize, pFmtetc ? "pFmtetc" : "NULL", pstgmed ? "pstgmed" : "NULL"); DBWIN(msg); #endif if (!m_stream) m_stream = pstgmed->pstm; return (m_control->OnData(m_propId, grfBSCF, m_stream, dwSize)); } STDMETHODIMP CDownloadSink::OnObjectAvailable(REFIID riid, IUnknown *punk) { return(E_NOTIMPL); } STDMETHODIMP CDownloadSink::OnLowResource(DWORD reserved) { m_binding->Abort(); return(S_OK); } STDMETHODIMP CDownloadSink::OnStopBinding(HRESULT hrError, LPCWSTR szError) { m_binding->Release(); m_binding = 0; m_control->Release(); m_control = 0; return(NOERROR); } // class CInternetControl CInternetControl::CInternetControl(IUnknown * pUnkOuter, int iPrimaryDispatch, void * pMainInterface) : COleControl(pUnkOuter,iPrimaryDispatch,pMainInterface) { m_host = 0; m_readyState = READYSTATE_LOADING; } CInternetControl::~CInternetControl() { if (m_host) m_host->Release(); } HRESULT CInternetControl::InternalQueryInterface(REFIID riid, void **ppvObjOut) { *ppvObjOut = NULL; return COleControl::InternalQueryInterface(riid, ppvObjOut); } HRESULT CInternetControl::GetBindHost() { if (m_host) return(NOERROR); // Try service provider first... IServiceProvider * serviceProvider = 0; HRESULT hr = m_pClientSite->QueryInterface(IID_IServiceProvider, (void**) &serviceProvider); if (SUCCEEDED(hr)) { hr = serviceProvider->QueryService(SID_IBindHost, IID_IBindHost, (void**) &m_host); serviceProvider->Release(); } if (FAILED(hr)) { // Some containers put IBindHost directly on the client site hr = m_pClientSite->QueryInterface (IID_IBindHost, (void**) &m_host); } return(hr); } HRESULT CInternetControl::GetAMoniker(LPOLESTR url, IMoniker ** ppmkr) { #if 0 11-Jun-1997 [ralphw] m_host->CreateMoniker generates a compiler error. Doesn't exist in any header file that I can find. HRESULT hr = GetBindHost(); if( SUCCEEDED(hr) ) hr = m_host->CreateMoniker(url,NULL, ppmkr,0); if( FAILED(hr) ) { // FUTURE: This really should be a call to MkParseDisplayNameEx!!! hr = ::CreateURLMoniker(0,url,ppmkr); // hr = ::MkParseDisplayNameEx(0, url, 0, ppmkr); } return( hr ); #else return ::CreateURLMoniker(0,url,ppmkr); #endif } HRESULT CInternetControl::SetupDownload(LPOLESTR url, DISPID propId) { CHECK_POINTER(url); IMoniker * pmkr; HRESULT hr = GetAMoniker(url, &pmkr); IBindCtx * pBindCtx = 0; if (SUCCEEDED(hr)) { hr = ::CreateBindCtx(0, &pBindCtx); } CDownloadSink * sink = 0; if (SUCCEEDED(hr)) { sink = new CDownloadSink(0, this, propId); if (sink) sink->AddRef(); } if (SUCCEEDED(hr) && !sink) hr = E_OUTOFMEMORY; if (SUCCEEDED(hr)) { hr = ::RegisterBindStatusCallback(pBindCtx, sink, 0, 0); } IStream * strm = 0; if (SUCCEEDED(hr)) hr = pmkr->BindToStorage(pBindCtx, 0, IID_IStream, (void**) &strm); if (strm) strm->Release(); if (pBindCtx) pBindCtx->Release(); if (FAILED(hr) && sink) sink->Release(); return(hr); } HRESULT CInternetControl::OnProgress( DISPID, ULONG progress, ULONG themax, ULONG, LPCWSTR) { return(NOERROR); } HRESULT CInternetControl::FireReadyStateChange(LONG newState) { FireEvent(&::rgEvents[InternetEvent_ReadyStateChange], m_readyState = newState); return(S_OK); } HRESULT CInternetControl::FireProgress(ULONG dwAmount) { FireEvent(&::rgEvents[InternetEvent_Progress], dwAmount); return(S_OK); }