INTERNET.CPP
//=--------------------------------------------------------------------------= 
// Internet.Cpp 
//=--------------------------------------------------------------------------= 
// Copyright 1995 - 1998 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); 
}