Windows-Server-2003/shell/shdocvw/bindcb.cpp

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);
}