1012 lines
30 KiB
C++
1012 lines
30 KiB
C++
|
|
//*********************************************************************
|
|
//* Microsoft Windows **
|
|
//* Copyright(c) Microsoft Corp., 1996 **
|
|
//*********************************************************************
|
|
|
|
// the CStubBindStatusCallback implements IBindStatusCallback,
|
|
// IHttpNegotiate. We use it to make a "fake" bind status callback
|
|
// object when we have headers and post data we would like to apply
|
|
// to a navigation. We supply this IBindStatusCallback object, and
|
|
// the URL moniker asks us for headers and post data and use those in
|
|
// the transaction.
|
|
|
|
#include "priv.h"
|
|
#include "sccls.h"
|
|
#include "bindcb.h"
|
|
|
|
CStubBindStatusCallback::CStubBindStatusCallback(LPCWSTR pwzHeaders,LPCBYTE pPostData,
|
|
DWORD cbPostData, VARIANT_BOOL bOfflineProperty, VARIANT_BOOL bSilentProperty, BOOL bHyperlink,
|
|
DWORD grBindFlags) : _cRef(1)
|
|
// _pszHeaders(NULL), _hszPostData(NULL), _cbPostData(0) (don't need to zero-init)
|
|
{
|
|
// this is a standalone COM object; need to maintain ref count on our
|
|
// DLL to ensure it doesn't unload
|
|
DllAddRef();
|
|
|
|
if (pwzHeaders) {
|
|
_pszHeaders = StrDup(pwzHeaders); // allocate for a permanent copy
|
|
}
|
|
|
|
if (pPostData && cbPostData) {
|
|
// make a copy of post data and store it
|
|
_hszPostData = GlobalAlloc(GPTR,cbPostData);
|
|
if (_hszPostData) {
|
|
memcpy((LPVOID) _hszPostData,pPostData,cbPostData);
|
|
_cbPostData = cbPostData;
|
|
}
|
|
}
|
|
|
|
_bFrameIsOffline = bOfflineProperty ? TRUE : FALSE;
|
|
_bFrameIsSilent = bSilentProperty ? TRUE : FALSE;
|
|
_bHyperlink = bHyperlink ? TRUE : FALSE;
|
|
_grBindFlags = grBindFlags;
|
|
TraceMsg(TF_SHDLIFE, "ctor CStubBindStatusCallback %x", this);
|
|
}
|
|
|
|
HRESULT CStubBSC_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
|
|
{
|
|
// aggregation checking is handled in class factory
|
|
|
|
CStubBindStatusCallback * pbsc = new CStubBindStatusCallback(NULL, NULL, 0, FALSE, FALSE, TRUE, 0);
|
|
if (pbsc) {
|
|
*ppunk = (IBindStatusCallback *)pbsc;
|
|
return S_OK;
|
|
}
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
CStubBindStatusCallback::~CStubBindStatusCallback()
|
|
{
|
|
TraceMsg(TF_SHDLIFE, "dtor CBindStatusCallback %x", this);
|
|
|
|
_FreeHeadersAndPostData(); // free any data we still have in this object
|
|
|
|
// release ref count on DLL
|
|
DllRelease();
|
|
}
|
|
|
|
STDMETHODIMP CStubBindStatusCallback::QueryInterface(REFIID riid,
|
|
LPVOID * ppvObj)
|
|
{
|
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_IBindStatusCallback)) {
|
|
*ppvObj = SAFECAST(this, IBindStatusCallback*);
|
|
} else if (IsEqualIID(riid, IID_IHttpNegotiate)) {
|
|
*ppvObj = SAFECAST(this, IHttpNegotiate*);
|
|
} else if (IsEqualIID(riid, IID_IMarshal)) {
|
|
*ppvObj = SAFECAST(this, IMarshal*);
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
AddRef(); // handing out an interface on ourselves; bump up ref count
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CStubBindStatusCallback::AddRef(void)
|
|
{
|
|
_cRef++;
|
|
TraceMsg(TF_SHDREF, "CStubBindStatusCallback(%x)::AddRef called, new _cRef=%d", this, _cRef);
|
|
|
|
return _cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CStubBindStatusCallback::Release(void)
|
|
{
|
|
_cRef--;
|
|
TraceMsg(TF_SHDREF, "CStubBindStatusCallback(%x)::Release called, new _cRef=%d", this, _cRef);
|
|
|
|
if (_cRef > 0)
|
|
return _cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Implementation of IBindStatusCallback begins here
|
|
//
|
|
|
|
// implements IBindStatusCallback::OnStartBinding
|
|
STDMETHODIMP CStubBindStatusCallback::OnStartBinding(DWORD grfBSCOption,IBinding *pib)
|
|
{
|
|
return S_OK; // we don't care
|
|
}
|
|
|
|
// implements IBindStatusCallback::GetPriority
|
|
STDMETHODIMP CStubBindStatusCallback::GetPriority(LONG *pnPriority)
|
|
{
|
|
*pnPriority = NORMAL_PRIORITY_CLASS;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// implements IBindStatusCallback::OnLowResource
|
|
STDMETHODIMP CStubBindStatusCallback::OnLowResource(DWORD reserved)
|
|
{
|
|
return S_OK; // we don't care
|
|
}
|
|
|
|
// implements IBindStatusCallback::OnProgress
|
|
STDMETHODIMP CStubBindStatusCallback::OnProgress(ULONG ulProgress,ULONG ulProgressMax,
|
|
ULONG ulStatusCode,LPCWSTR szStatusText)
|
|
{
|
|
return S_OK; // we don't care
|
|
}
|
|
|
|
// implements IBindStatusCallback::OnStopBinding
|
|
STDMETHODIMP CStubBindStatusCallback::OnStopBinding(HRESULT hresult,LPCWSTR szError)
|
|
{
|
|
return S_OK; // we don't care
|
|
}
|
|
|
|
// implements IBindStatusCallback::GetBindInfo
|
|
STDMETHODIMP CStubBindStatusCallback::GetBindInfo(DWORD *grfBINDF,BINDINFO *pbindinfo)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (!grfBINDF || !pbindinfo || !pbindinfo->cbSize)
|
|
return E_INVALIDARG;
|
|
|
|
// call helper function to do fill in BINDINFO struct with appropriate
|
|
// binding data
|
|
*grfBINDF = _grBindFlags;
|
|
hr = BuildBindInfo(grfBINDF,pbindinfo,_hszPostData,_cbPostData, _bFrameIsOffline, _bFrameIsSilent, _bHyperlink,
|
|
(IBindStatusCallback *) this);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// implements IBindStatusCallback::OnDataAvailable
|
|
STDMETHODIMP CStubBindStatusCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize,
|
|
FORMATETC *pformatetc, STGMEDIUM *pstgmed)
|
|
{
|
|
ASSERT(FALSE); // should never get called here!
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CStubBindStatusCallback::OnObjectAvailable(REFIID riid,IUnknown *punk)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Implementation of IHttpNegotiate begins here
|
|
//
|
|
|
|
// implements IHttpNegotiate::BeginningTransaction
|
|
STDMETHODIMP CStubBindStatusCallback::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders,
|
|
DWORD dwReserved, LPWSTR *ppwzAdditionalHeaders)
|
|
{
|
|
// call helper function
|
|
return BuildAdditionalHeaders(_pszHeaders,(LPCWSTR *) ppwzAdditionalHeaders);
|
|
}
|
|
|
|
// implements IHttpNegotiate::OnResponse
|
|
STDMETHODIMP CStubBindStatusCallback::OnResponse(DWORD dwResponseCode, LPCWSTR szResponseHeaders,
|
|
LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
|
|
{
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Additional methods on our class begin here
|
|
//
|
|
|
|
STDMETHODIMP CStubBindStatusCallback::_FreeHeadersAndPostData()
|
|
{
|
|
if (_pszHeaders) {
|
|
LocalFree((HGLOBAL) _pszHeaders);
|
|
_pszHeaders = NULL;
|
|
}
|
|
|
|
if (_hszPostData) {
|
|
GlobalFree(_hszPostData);
|
|
_hszPostData = NULL;
|
|
_cbPostData = 0;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CStubBindStatusCallback::_CanMarshalIID
|
|
//
|
|
// Synopsis: Checks whether this object supports marshalling this IID.
|
|
//
|
|
// Arguments: [riid] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 1-19-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
inline BOOL CStubBindStatusCallback::_CanMarshalIID(REFIID riid)
|
|
{
|
|
// keep this in sync with the QueryInterface
|
|
return (BOOL) (IsEqualIID(riid,IID_IBindStatusCallback) ||
|
|
IsEqualIID(riid,IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_IHttpNegotiate));
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CStubBindStatusCallback::_ValidateMarshalParams
|
|
//
|
|
// Synopsis: Validates the standard set parameters that are passed into most
|
|
// of the IMarshal methods
|
|
//
|
|
// Arguments: [riid] --
|
|
// [pvInterface] --
|
|
// [dwDestContext] --
|
|
// [pvDestContext] --
|
|
// [mshlflags] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 1-19-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CStubBindStatusCallback::_ValidateMarshalParams(REFIID riid,void *pvInterface,
|
|
DWORD dwDestContext,void *pvDestContext,DWORD mshlflags)
|
|
{
|
|
|
|
HRESULT hr = NOERROR;
|
|
|
|
if (_CanMarshalIID(riid))
|
|
{
|
|
// 10/02/96 chrisfra: ask johannp, should we be supporting future contexts
|
|
// via CoGetStandardMarshal?
|
|
|
|
ASSERT((dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_LOCAL || dwDestContext == MSHCTX_NOSHAREDMEM));
|
|
ASSERT((mshlflags == MSHLFLAGS_NORMAL || mshlflags == MSHLFLAGS_TABLESTRONG));
|
|
|
|
if ( (dwDestContext != MSHCTX_INPROC && dwDestContext != MSHCTX_LOCAL && dwDestContext != MSHCTX_NOSHAREDMEM)
|
|
|| (mshlflags != MSHLFLAGS_NORMAL && mshlflags != MSHLFLAGS_TABLESTRONG))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IMarshal methods
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CStubBindStatusCallback::GetUnmarshalClass
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [riid] --
|
|
// [pvInterface] --
|
|
// [dwDestContext] --
|
|
// [pvDestContext] --
|
|
// [mshlflags] --
|
|
// [pCid] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 1-19-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CStubBindStatusCallback::GetUnmarshalClass(REFIID riid,void *pvInterface,
|
|
DWORD dwDestContext,void *pvDestContext,DWORD mshlflags,CLSID *pCid)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = _ValidateMarshalParams(riid, pvInterface, dwDestContext,pvDestContext, mshlflags);
|
|
if (hr == NOERROR)
|
|
{
|
|
*pCid = (CLSID) CLSID_CStubBindStatusCallback;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CStubBindStatusCallback::GetMarshalSizeMax
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [void] --
|
|
// [pvInterface] --
|
|
// [dwDestContext] --
|
|
// [pvDestContext] --
|
|
// [mshlflags] --
|
|
// [pSize] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 1-19-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CStubBindStatusCallback::GetMarshalSizeMax(REFIID riid,void *pvInterface,
|
|
DWORD dwDestContext,void *pvDestContext,DWORD mshlflags,DWORD *pSize)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (pSize == NULL)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
hr = _ValidateMarshalParams(riid, pvInterface, dwDestContext,pvDestContext, mshlflags);
|
|
if (hr == NOERROR)
|
|
{
|
|
|
|
// size of fBSCBFlags, grBindFlags, postdata, headers.
|
|
*pSize = (sizeof(DWORD) + 3 * sizeof(DWORD)) + _cbPostData ;
|
|
if (_pszHeaders)
|
|
*pSize += ((lstrlen(_pszHeaders) + 1) * sizeof(*_pszHeaders));
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CStubBindStatusCallback::MarshalInterface
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [REFIID] --
|
|
// [riid] --
|
|
// [DWORD] --
|
|
// [void] --
|
|
// [DWORD] --
|
|
// [mshlflags] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 1-19-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CStubBindStatusCallback::MarshalInterface(IStream *pistm,REFIID riid,
|
|
void *pvInterface,DWORD dwDestContext,
|
|
void *pvDestContext,DWORD mshlflags)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cbLen;
|
|
DWORD fBSCBFlags;
|
|
|
|
hr = _ValidateMarshalParams(riid, pvInterface, dwDestContext,pvDestContext, mshlflags);
|
|
if (hr != NOERROR) goto exitPoint;
|
|
|
|
// Write _grBindFlags
|
|
hr = pistm->Write(&_grBindFlags, sizeof(DWORD), NULL);
|
|
if (hr != NOERROR) goto exitPoint;
|
|
|
|
// Write fBSCBFlags
|
|
|
|
fBSCBFlags = (_bFrameIsOffline ? 1 : 0) + (_bFrameIsSilent ? 2 : 0) ;
|
|
|
|
hr = pistm->Write(&fBSCBFlags, sizeof(DWORD), NULL);
|
|
if (hr != NOERROR) goto exitPoint;
|
|
|
|
// Write headers
|
|
|
|
cbLen = (_pszHeaders ? (lstrlen(_pszHeaders) + 1) * sizeof(TCHAR) : 0);
|
|
hr = pistm->Write(&cbLen, sizeof(DWORD), NULL);
|
|
if (hr != NOERROR) goto exitPoint;
|
|
if (cbLen != 0)
|
|
{
|
|
hr = pistm->Write(_pszHeaders, cbLen, NULL);
|
|
if (hr != NOERROR) goto exitPoint;
|
|
}
|
|
|
|
// Write PostData
|
|
|
|
hr = pistm->Write(&_cbPostData, sizeof(DWORD), NULL);
|
|
if (hr != NOERROR) goto exitPoint;
|
|
if (_cbPostData != 0)
|
|
{
|
|
hr = pistm->Write(_hszPostData, _cbPostData, NULL);
|
|
if (hr != NOERROR) goto exitPoint;
|
|
}
|
|
|
|
exitPoint:
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CStubBindStatusCallback::UnmarshalInterface
|
|
//
|
|
// Synopsis: Unmarshals an Urlmon interface out of a stream
|
|
//
|
|
// Arguments: [REFIID] --
|
|
// [void] --
|
|
// [ppvObj] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 1-19-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CStubBindStatusCallback::UnmarshalInterface(IStream *pistm, REFIID riid, void ** ppvObj)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
DWORD fBSCBFlags;
|
|
|
|
if (ppvObj == NULL)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else if (! _CanMarshalIID(riid))
|
|
{
|
|
*ppvObj = NULL;
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
DWORD cbLen;
|
|
|
|
// Free old values, if any
|
|
|
|
_FreeHeadersAndPostData();
|
|
|
|
// Read _grBindFlags
|
|
|
|
hr = pistm->Read(&fBSCBFlags, sizeof(DWORD), NULL);
|
|
if (hr != NOERROR) goto exitPoint;
|
|
_grBindFlags = fBSCBFlags;
|
|
|
|
// Read m_fBSCBFlags
|
|
|
|
hr = pistm->Read(&fBSCBFlags, sizeof(DWORD), NULL);
|
|
if (hr != NOERROR) goto exitPoint;
|
|
_bFrameIsOffline = fBSCBFlags & 1 ? 1:0;
|
|
_bFrameIsSilent = fBSCBFlags & 2 ? 1:0;
|
|
|
|
// Read headers
|
|
|
|
hr = pistm->Read(&cbLen, sizeof(DWORD), NULL);
|
|
if (hr != NOERROR) goto exitPoint;
|
|
if (cbLen != 0)
|
|
{
|
|
LPTSTR pszData;
|
|
|
|
pszData = (LPTSTR) LocalAlloc(LPTR, cbLen);
|
|
if (pszData == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exitPoint;
|
|
}
|
|
hr = pistm->Read(pszData, cbLen, 0);
|
|
if (hr != NOERROR)
|
|
{
|
|
LocalFree(pszData);
|
|
pszData = NULL;
|
|
goto exitPoint;
|
|
}
|
|
_pszHeaders = pszData;
|
|
}
|
|
|
|
// Read PostData
|
|
|
|
hr = pistm->Read(&cbLen, sizeof(DWORD), NULL);
|
|
if (hr != NOERROR) goto exitPoint;
|
|
if (cbLen != 0)
|
|
{
|
|
HGLOBAL hszData;
|
|
|
|
// POST data must be HGLOBAL because the StgMedium requires it
|
|
// see bindcb.cpp ::GetBindInfo()
|
|
// This will be freed by the Moniker when it's done with it.
|
|
|
|
|
|
hszData = GlobalAlloc(GPTR,cbLen);
|
|
if (hszData == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exitPoint;
|
|
}
|
|
hr = pistm->Read(hszData, cbLen, 0);
|
|
if (hr != NOERROR)
|
|
{
|
|
GlobalFree(hszData);
|
|
hszData = NULL;
|
|
goto exitPoint;
|
|
}
|
|
_hszPostData = hszData;
|
|
_cbPostData = cbLen;
|
|
}
|
|
|
|
|
|
// call QI to get the requested interface
|
|
hr = QueryInterface(riid, ppvObj);
|
|
}
|
|
exitPoint:
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CStubBindStatusCallback::ReleaseMarshalData(IStream *pStm)
|
|
{
|
|
// 10/02/96 chrisfra: ask Johannp if this should be seeking past EOD
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CStubBindStatusCallback::DisconnectObject(DWORD dwReserved)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//
|
|
// Global helper functions
|
|
//
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: fOnProxy
|
|
|
|
SYNOPSIS: returns TRUE if we are have proxy enabled
|
|
|
|
|
|
********************************************************************/
|
|
BOOL fOnProxy()
|
|
{
|
|
// are we on a proxy?
|
|
BOOL fRetOnProxy = FALSE;
|
|
DWORD dwValue;
|
|
DWORD dwSize = SIZEOF(dwValue);
|
|
BOOL fDefault = FALSE;
|
|
|
|
SHRegGetUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
|
|
TEXT("ProxyEnable"), NULL, (LPBYTE)&dwValue, &dwSize, FALSE, (LPVOID) &fDefault, SIZEOF(fDefault));
|
|
fRetOnProxy = dwValue;
|
|
|
|
return fRetOnProxy;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: SetBindfFlagsBasedOnAmbient
|
|
|
|
SYNOPSIS: sets BINDF_OFFLINE if ambient offline and
|
|
not-connected and sets BINDF_GETFROMCACHE_IF_NET_FAIL
|
|
if ambient offline and connected
|
|
|
|
|
|
********************************************************************/
|
|
void SetBindfFlagsBasedOnAmbient(BOOL fAmbientOffline, DWORD *grfBINDF)
|
|
{
|
|
if (fAmbientOffline)
|
|
{
|
|
DWORD dwConnectedStateFlags;
|
|
|
|
// We want to set the offline bindf flag if the ambient flag is set
|
|
// and we're currently not connected.
|
|
//
|
|
// If either of these conditions is not true, clear the offline flag
|
|
// as mshtml may have previously set it.
|
|
if (FALSE == InternetGetConnectedState(&dwConnectedStateFlags, 0))
|
|
{
|
|
*grfBINDF |= BINDF_OFFLINEOPERATION;
|
|
*grfBINDF &= ~BINDF_GETFROMCACHE_IF_NET_FAIL;
|
|
}
|
|
else
|
|
{
|
|
*grfBINDF |= BINDF_GETFROMCACHE_IF_NET_FAIL;
|
|
*grfBINDF &= ~BINDF_OFFLINEOPERATION;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*grfBINDF &= ~BINDF_OFFLINEOPERATION;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BuildBindInfo
|
|
|
|
SYNOPSIS: Fills out a BINDINFO structure for a URL moniker
|
|
|
|
NOTES: The point of having this in a global helper function is
|
|
so we don't have to duplicate this code in multiple
|
|
implementations of IBindStatusCallback.
|
|
|
|
The caller must pass in an IUnknown to be used as the
|
|
pUnkForRelease in the STGMEDIUM for post data. If there
|
|
is post data, this function will AddRef the passed-in
|
|
IUnknown and return it in the STGMEDIUM structure. The
|
|
caller (or someone else, if the caller hands it off) must
|
|
ultimately call Release on pbindinfo->stgmediumData.pUnkForRelease.
|
|
|
|
********************************************************************/
|
|
HRESULT BuildBindInfo(DWORD *grfBINDF,BINDINFO *pbindinfo,HGLOBAL hszPostData,
|
|
DWORD cbPostData, BOOL bFrameIsOffline, BOOL bFrameIsSilent, BOOL bHyperlink, LPUNKNOWN pUnkForRelease)
|
|
{
|
|
DWORD dwConnectedStateFlags = 0;
|
|
ASSERT(grfBINDF);
|
|
ASSERT(pbindinfo);
|
|
ASSERT(pUnkForRelease);
|
|
|
|
HRESULT hres=S_OK;
|
|
|
|
if (!grfBINDF || !pbindinfo || !pbindinfo->cbSize)
|
|
return E_INVALIDARG;
|
|
|
|
// clear BINDINFO except cbSize
|
|
ASSERT(sizeof(*pbindinfo) == pbindinfo->cbSize);
|
|
DWORD cbSize = pbindinfo->cbSize;
|
|
ZeroMemory(pbindinfo, cbSize);
|
|
pbindinfo->cbSize = cbSize;
|
|
|
|
*grfBINDF |= BINDF_ASYNCHRONOUS;
|
|
|
|
if (bHyperlink)
|
|
*grfBINDF |= BINDF_HYPERLINK;
|
|
|
|
|
|
SetBindfFlagsBasedOnAmbient(bFrameIsOffline, grfBINDF);
|
|
|
|
if (bFrameIsSilent)
|
|
*grfBINDF |= BINDF_NO_UI;
|
|
|
|
// default method is GET. Valid ones are _GET, _PUT, _POST, _CUSTOM
|
|
pbindinfo->dwBindVerb = BINDVERB_GET;
|
|
|
|
// get IE-wide UTF-8 policy by calling urlmon
|
|
DWORD dwIE = URL_ENCODING_NONE;
|
|
DWORD dwOutLen = sizeof(DWORD);
|
|
if (S_OK == UrlMkGetSessionOption(
|
|
URLMON_OPTION_URL_ENCODING,
|
|
&dwIE,
|
|
sizeof(DWORD),
|
|
&dwOutLen,
|
|
NULL))
|
|
{
|
|
if (dwIE == URL_ENCODING_ENABLE_UTF8)
|
|
{
|
|
pbindinfo->dwOptions |= BINDINFO_OPTIONS_ENABLE_UTF8;
|
|
}
|
|
else if (dwIE == URL_ENCODING_DISABLE_UTF8)
|
|
{
|
|
pbindinfo->dwOptions |= BINDINFO_OPTIONS_DISABLE_UTF8;
|
|
}
|
|
}
|
|
|
|
// if we have postdata set, then we assume this is a POST verb
|
|
|
|
if (hszPostData)
|
|
{
|
|
pbindinfo->dwBindVerb = BINDVERB_POST;
|
|
pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
|
|
pbindinfo->stgmedData.hGlobal = hszPostData;
|
|
// this count should *NOT* include the terminating NULL
|
|
pbindinfo->cbstgmedData = cbPostData;
|
|
pbindinfo->stgmedData.pUnkForRelease = pUnkForRelease;
|
|
// addref on the IUnknown that's holding onto this data so
|
|
// it knows to stick around; caller must call Release
|
|
// on the pUnkForRelease when done.
|
|
pUnkForRelease->AddRef();
|
|
|
|
// We will still cache the response, but we do not want to
|
|
// read from cache for a POST transaction. This will keep us
|
|
// from reading from the cache.
|
|
*grfBINDF |= BINDF_GETNEWESTVERSION | BINDF_CONTAINER_NOWRITECACHE;
|
|
} else {
|
|
ASSERT(pbindinfo->stgmedData.tymed == TYMED_NULL);
|
|
ASSERT(pbindinfo->stgmedData.hGlobal == NULL);
|
|
ASSERT(pbindinfo->stgmedData.pUnkForRelease == NULL);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
#define HDR_LANGUAGE TEXT("Accept-Language:")
|
|
#define CRLF TEXT("\x0D\x0A")
|
|
#define HDR_LANGUAGE_CRLF TEXT("Accept-Language: %s\x0D\x0A")
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BuildAdditionalHeaders
|
|
|
|
SYNOPSIS: Builds HTTP headers to be given to URL moniker
|
|
|
|
ENTRY: pszOurExtraHeaders - headers that we explicitly want to add
|
|
*ppwzCombinedHeadersOut - on exit, filled in with
|
|
buffer of default headers plus pszOurExtraHeaders.
|
|
|
|
NOTES: The point of having this in a global helper function is
|
|
so we don't have to duplicate this code in multiple
|
|
implementations of IBindStatusCallback.
|
|
|
|
The caller must free *ppwzCombinedHeaders by passing
|
|
to URLMON, or calling OleFree
|
|
|
|
********************************************************************/
|
|
HRESULT BuildAdditionalHeaders(LPCTSTR pszOurExtraHeaders,LPCWSTR * ppwzCombinedHeadersOut)
|
|
{
|
|
|
|
TCHAR szLanguage[80]; // what limit on language?
|
|
DWORD dwLanguage = ARRAYSIZE(szLanguage);
|
|
static const TCHAR hdr_language[] = HDR_LANGUAGE_CRLF;
|
|
TCHAR szHeader[ARRAYSIZE(hdr_language) + ARRAYSIZE(szLanguage)]; // NOTE format string length > wnsprintf length
|
|
int cchHeaders = 0;
|
|
int cchAddedHeaders = 1; // implied '\0'
|
|
HRESULT hres = NOERROR;
|
|
|
|
if (!ppwzCombinedHeadersOut)
|
|
return E_FAIL;
|
|
|
|
*ppwzCombinedHeadersOut = NULL;
|
|
|
|
// If there is no language in the registry, *WE DO NOT SEND THIS HEADER*
|
|
|
|
// S_OK means szLanguage filled in and returned
|
|
// S_FALSE means call succeeded, but there was no language set
|
|
// E_* is an error
|
|
// We treat S_FALSE and E_* the same, no language header sent.
|
|
if (GetAcceptLanguages(szLanguage, &dwLanguage) == S_OK)
|
|
{
|
|
StringCchPrintf(szHeader, ARRAYSIZE(szHeader), hdr_language, szLanguage);
|
|
cchHeaders = lstrlen(szHeader) + 1;
|
|
}
|
|
|
|
if (pszOurExtraHeaders)
|
|
{
|
|
cchAddedHeaders = lstrlen(pszOurExtraHeaders) + 1;
|
|
}
|
|
|
|
// If we have headers we added or were sent in, we need to Wide 'em and
|
|
// give 'em back
|
|
if (cchAddedHeaders > 1 || cchHeaders > 0)
|
|
{
|
|
WCHAR *pwzHeadersForUrlmon = (WCHAR *)CoTaskMemAlloc(sizeof(WCHAR) * (cchHeaders + cchAddedHeaders - 1));
|
|
if (pwzHeadersForUrlmon)
|
|
{
|
|
if (cchHeaders)
|
|
{
|
|
StrCpyN(pwzHeadersForUrlmon, szHeader, cchHeaders);
|
|
}
|
|
if (pszOurExtraHeaders)
|
|
{
|
|
if (cchHeaders)
|
|
{
|
|
StrCpyN(pwzHeadersForUrlmon + cchHeaders - 1,
|
|
pszOurExtraHeaders, cchAddedHeaders);
|
|
}
|
|
else
|
|
{
|
|
StrCpyN(pwzHeadersForUrlmon, pszOurExtraHeaders, cchAddedHeaders - 1);
|
|
}
|
|
}
|
|
if (cchHeaders || pszOurExtraHeaders)
|
|
*ppwzCombinedHeadersOut = pwzHeadersForUrlmon;
|
|
}
|
|
else
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
hres = pszOurExtraHeaders == NULL ? S_OK : E_FAIL;
|
|
|
|
return hres;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: GetHeadersAndPostData
|
|
|
|
SYNOPSIS: Gets HTTP headers and post data from an IBindStatusCallback
|
|
|
|
ENTRY: IBindStatusCallback - object to ask for headers and post data
|
|
ppszHeaders - on exit, filled in with pointer to headers,
|
|
or NULL if none
|
|
pstgPostData - pointer to a STGMEDIUM to be filled in with post
|
|
data, if any.
|
|
|
|
|
|
NOTES: The caller is responsible for:
|
|
- calling LocalFree on *ppszHeaders when done with them
|
|
- calling ReleaseStgMedium on pstgPostData when done
|
|
with it
|
|
|
|
********************************************************************/
|
|
HRESULT GetHeadersAndPostData(IBindStatusCallback * pBindStatusCallback,
|
|
LPTSTR * ppszHeaders, STGMEDIUM * pstgPostData, DWORD * pdwPostData, BOOL* pfIsPost)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
ASSERT(pBindStatusCallback);
|
|
ASSERT(ppszHeaders);
|
|
ASSERT(pstgPostData);
|
|
ASSERT(pdwPostData);
|
|
|
|
// clear the out parameters
|
|
*ppszHeaders = NULL;
|
|
|
|
DWORD grfBINDF;
|
|
IHttpNegotiate *pinegotiate;
|
|
BINDINFO binfo;
|
|
binfo.cbSize = sizeof(binfo);
|
|
ZeroMemory(pstgPostData, sizeof(*pstgPostData));
|
|
*pdwPostData = 0;
|
|
|
|
hr=pBindStatusCallback->GetBindInfo(&grfBINDF, &binfo);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
// copy STGMEDIUM with post data to caller
|
|
*pstgPostData = binfo.stgmedData;
|
|
*pdwPostData = binfo.cbstgmedData;
|
|
|
|
// clear these so ReleaseBindInfo won't wack it since we are giving it to the caller
|
|
ZeroMemory(&binfo.stgmedData, sizeof(STGMEDIUM));
|
|
binfo.cbstgmedData = 0;
|
|
|
|
if (pfIsPost)
|
|
{
|
|
if (*pdwPostData)
|
|
*pfIsPost = TRUE;
|
|
else
|
|
*pfIsPost = FALSE;
|
|
}
|
|
|
|
hr = pBindStatusCallback->QueryInterface(IID_IHttpNegotiate, (LPVOID *)&pinegotiate);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR *pwzAdditionalHeaders = NULL;
|
|
WCHAR wzNull[1];
|
|
|
|
wzNull[0] = 0;
|
|
hr=pinegotiate->BeginningTransaction(wzNull, wzNull, 0, &pwzAdditionalHeaders);
|
|
if (SUCCEEDED(hr) && pwzAdditionalHeaders)
|
|
{
|
|
DWORD cchHeaders;
|
|
|
|
cchHeaders = lstrlen(pwzAdditionalHeaders) + 1;
|
|
|
|
// they should *NEVER* be specifying more than a few hundred
|
|
// bytes or they're going to fail with a number of HTTP servers!
|
|
|
|
LPTSTR pszHeaders = (TCHAR *)LocalAlloc(LPTR, cchHeaders*sizeof(TCHAR));
|
|
if (pszHeaders)
|
|
{
|
|
LPTSTR pszNext;
|
|
LPTSTR pszLine;
|
|
LPTSTR pszLast;
|
|
|
|
StrCpyN(pszHeaders, pwzAdditionalHeaders, cchHeaders);
|
|
pszLine = pszHeaders;
|
|
pszLast = pszHeaders + lstrlen(pszHeaders);
|
|
while (pszLine < pszLast)
|
|
{
|
|
pszNext = StrStrI(pszLine, CRLF);
|
|
if (pszNext == NULL)
|
|
{
|
|
// All Headers must be terminated in CRLF!
|
|
pszLine[0] = '\0';
|
|
break;
|
|
}
|
|
pszNext += 2;
|
|
if (!StrCmpNI(pszLine,HDR_LANGUAGE,16))
|
|
{
|
|
MoveMemory(pszLine, pszNext, ((pszLast - pszNext) + 1)*sizeof(TCHAR));
|
|
break;
|
|
}
|
|
pszLine = pszNext;
|
|
}
|
|
// Don't include empty headers
|
|
if (pszHeaders[0] == '\0')
|
|
{
|
|
LocalFree(pszHeaders);
|
|
pszHeaders = NULL;
|
|
}
|
|
}
|
|
OleFree(pwzAdditionalHeaders);
|
|
*ppszHeaders = pszHeaders;
|
|
}
|
|
pinegotiate->Release();
|
|
}
|
|
|
|
ReleaseBindInfo(&binfo);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: GetTopLevelBindStatusCallback
|
|
|
|
ENTRY: psp - IServiceProvider of ShellBrowser container to query
|
|
ppBindStatusCallback - if successful, filled in with
|
|
an IBindStatusCallback on exit
|
|
|
|
SYNOPSIS: Gets the IBindStatusCallback associated with this top
|
|
level browser. This works from within nested frames.
|
|
|
|
********************************************************************/
|
|
HRESULT GetTopLevelBindStatusCallback(IServiceProvider *psp, IBindStatusCallback **ppBindStatusCallback)
|
|
{
|
|
IHlinkFrame *phf;
|
|
HRESULT hr = psp->QueryService(SID_SHlinkFrame, IID_PPV_ARG(IHlinkFrame, &phf));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = IUnknown_QueryService(phf, IID_IHlinkFrame, IID_PPV_ARG(IBindStatusCallback, ppBindStatusCallback));
|
|
phf->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: GetTopLevelPendingBindStatusCallback
|
|
|
|
ENTRY: psp - IServiceProvider of ShellBrowser container to query
|
|
ppBindStatusCallback - if successful, filled in with
|
|
an IBindStatusCallback on exit
|
|
|
|
SYNOPSIS: Gets the IBindStatusCallback associated with this top
|
|
level browser. This works from within nested frames.
|
|
|
|
********************************************************************/
|
|
HRESULT GetTopLevelPendingBindStatusCallback(IServiceProvider *psp, IBindStatusCallback **ppBindStatusCallback)
|
|
{
|
|
IHlinkFrame *phf;
|
|
HRESULT hr = psp->QueryService(SID_SHlinkFrame, IID_PPV_ARG(IHlinkFrame, &phf));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = IUnknown_QueryService(phf, SID_PendingBindStatusCallback, IID_PPV_ARG(IBindStatusCallback, ppBindStatusCallback));
|
|
phf->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Global helper function to create a CStubBindStatusCallback
|
|
HRESULT CStubBindStatusCallback_Create(LPCWSTR pwzHeaders, LPCBYTE pPostData,
|
|
DWORD cbPostData, VARIANT_BOOL bFrameIsOffline, VARIANT_BOOL bFrameIsSilent, BOOL bHyperlink,
|
|
DWORD grBindFlags,
|
|
CStubBindStatusCallback ** ppBindStatusCallback)
|
|
{
|
|
ASSERT(ppBindStatusCallback);
|
|
|
|
*ppBindStatusCallback = new CStubBindStatusCallback(pwzHeaders,pPostData,
|
|
cbPostData, bFrameIsOffline, bFrameIsSilent, bHyperlink, grBindFlags);
|
|
|
|
return (*ppBindStatusCallback ? S_OK : E_OUTOFMEMORY);
|
|
}
|