427 lines
10 KiB
C++
427 lines
10 KiB
C++
//=--------------------------------------------------------------------------=
|
||
// Internet.Cpp
|
||
//=--------------------------------------------------------------------------=
|
||
// Copyright 1995-1996 Microsoft Corporation. All Rights Reserved.
|
||
//
|
||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||
// PARTICULAR PURPOSE.
|
||
//=--------------------------------------------------------------------------=
|
||
//
|
||
// contains internet helper classes CDownloadSink and CInternetControl
|
||
//
|
||
#include "IPServer.H"
|
||
#include "Internet.H"
|
||
#include "Util.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...
|
||
|
||
|
||
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
|
||
)
|
||
{
|
||
// CHECK_POINTER(control);
|
||
|
||
m_control = control;
|
||
m_control->AddRef();
|
||
|
||
m_propId = propId;
|
||
m_next = 0;
|
||
m_binding = 0;
|
||
m_ref = 0;
|
||
m_stream = 0;
|
||
}
|
||
|
||
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_PULLDATA;
|
||
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)\n",grfBSCF,dwSize,
|
||
pFmtetc ? "pFmtetc" : "NULL", pstgmed ? "pstgmed" : "NULL" );
|
||
OutputDebugString(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)
|
||
{
|
||
// BUGBUG: really should have this kind of harsh policy on this ...
|
||
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 )
|
||
{
|
||
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 );
|
||
}
|
||
|
||
|
||
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) )
|
||
{
|
||
// BUGBUG: There should be a define for 0x77
|
||
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::OnData( DISPID, DWORD,IStream *, DWORD)
|
||
{
|
||
return(NOERROR);
|
||
}
|
||
|
||
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);
|
||
}
|
||
|