WindowsXP-SP1/inetcore/urlmon/mon/mpxbsc.cxx
2020-09-30 16:53:49 +02:00

1638 lines
46 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996.
//
// File: MPXBSC.CXX
//
// Contents: Code to handle multiplexing multiple concurrent
// IBindStatusCallback interfaces.
//
// Classes: CBSCHolder
//
// Functions:
//
// History: 01-04-96 JoeS (Joe Souza) Created
// 01-15-96 JohannP (Johann Posch) Modified to new IBSC
//
//----------------------------------------------------------------------------
#include <mon.h>
#include "mpxbsc.hxx"
PerfDbgTag(tagCBSCHolder, "Urlmon", "Log CBSCHolder", DEB_BINDING);
HRESULT GetObjectParam(IBindCtx *pbc, LPOLESTR pszKey, REFIID riid, IUnknown **ppUnk);
//+---------------------------------------------------------------------------
//
// Function: UrlMonInvokeExceptionFilterMSN
//
// Synopsis:
//
// Arguments: [lCode] --
// [lpep] --
//
// Returns:
//
// History: 8-25-97 DanpoZ(Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
LONG UrlMonInvokeExceptionFilterMSN( DWORD lCode, LPEXCEPTION_POINTERS lpep )
{
DEBUG_ENTER((DBG_CALLBACK,
Int,
"UrlMonInvokeExceptionFilterMSN",
"%#x, %#x",
lCode, lpep
));
#if DBG == 1
DbgLog2(tagCBSCHolder, NULL, "Exception 0x%#x at address 0x%#x",
lCode, lpep->ExceptionRecord->ExceptionAddress);
DebugBreak();
#endif
LONG exr = EXCEPTION_CONTINUE_EXECUTION;
if( lCode == STATUS_ACCESS_VIOLATION )
{
char achProgname[256];
achProgname[0] = 0;
GetModuleFileNameA(NULL,achProgname,sizeof(achProgname));
if( StrStrI(achProgname, "msnviewr.exe") )
{
exr = EXCEPTION_EXECUTE_HANDLER;
}
}
DEBUG_LEAVE(exr);
return exr;
}
//+---------------------------------------------------------------------------
//
// Function: GetBSCHolder
//
// Synopsis: Returns a holder for IBindStatusCallback
//
// Arguments: [pBC] --
// [ppCBSHolder] --
//
// Returns:
//
// History:
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT GetBSCHolder(LPBC pBC, CBSCHolder **ppCBSHolder)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"GetBSCHolder",
"%#x, %#x",
pBC, ppCBSHolder
));
PerfDbgLog(tagCBSCHolder, NULL, "+GetBSCHolder");
UrlMkAssert((ppCBSHolder != NULL));
HRESULT hr;
CBSCHolder *pCBSCBHolder = NULL;
hr = GetObjectParam(pBC, REG_BSCB_HOLDER, IID_IBindStatusCallbackHolder, (IUnknown **)&pCBSCBHolder);
if (pCBSCBHolder == NULL)
{
pCBSCBHolder = new CBSCHolder;
if (!pCBSCBHolder)
{
hr = E_OUTOFMEMORY;
}
else
{
hr = pBC->RegisterObjectParam(REG_BSCB_HOLDER, (IBindStatusCallback *) pCBSCBHolder);
*ppCBSHolder = pCBSCBHolder;
}
}
else
{
*ppCBSHolder = pCBSCBHolder;
}
PerfDbgLog1(tagCBSCHolder, NULL, "-GetBSCHolder (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
CBSCHolder::CBSCHolder(void) : _CRefs(), _cElements(0)
{
DEBUG_ENTER((DBG_CALLBACK,
None,
"CBSCHolder::CBSCHolder",
"this=%#x",
this
));
_pCBSCNode = NULL;
_fBindStarted = FALSE;
_fBindStopped = FALSE;
_fHttpNegotiate = FALSE;
_fAuthenticate = FALSE;
_fHttpNegotiate2 = FALSE;
DEBUG_LEAVE(0);
}
CBSCHolder::~CBSCHolder(void)
{
DEBUG_ENTER((DBG_CALLBACK,
None,
"CBSCHolder::~CBSCHolder",
"this=%#x",
this
));
CBSCNode *pNode, *pNextNode;
pNode = _pCBSCNode;
while (pNode)
{
pNextNode = pNode->GetNextNode();
delete pNode;
pNode = pNextNode;
}
DEBUG_LEAVE(0);
}
STDMETHODIMP CBSCHolder::QueryInterface(REFIID riid, void **ppvObj)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IUnknown::QueryInterface",
"this=%#x, %#x, %#x",
this, &riid, ppvObj
));
VDATEPTROUT(ppvObj, void *);
VDATETHIS(this);
HRESULT hr = NOERROR;
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::QueryInterface");
if ( (riid == IID_IUnknown)
|| (riid == IID_IBindStatusCallback)
|| (riid == IID_IBindStatusCallbackHolder) )
{
// the holder is not marshalled!!
*ppvObj = (void*)(IBindStatusCallback *) this;
}
else if (riid == IID_IServiceProvider)
{
*ppvObj = (void*)(IServiceProvider *) this;
}
else if (riid == IID_IHttpNegotiate)
{
*ppvObj = (void*)(IHttpNegotiate *) this;
}
else if (riid == IID_IHttpNegotiate2)
{
*ppvObj = (void*)(IHttpNegotiate2 *) this;
}
else if (riid == IID_IAuthenticate)
{
*ppvObj = (void*)(IAuthenticate *) this;
}
else
{
*ppvObj = NULL;
hr = E_NOINTERFACE;
}
if (hr == NOERROR)
{
AddRef();
}
PerfDbgLog1(tagCBSCHolder, this, "-CBSCHolder::QueryInterface (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
STDMETHODIMP_(ULONG) CBSCHolder::AddRef(void)
{
DEBUG_ENTER((DBG_CALLBACK,
Dword,
"CBSCHolder::IUnknown::AddRef",
"this=%#x",
this
));
LONG lRet = ++_CRefs;
PerfDbgLog1(tagCBSCHolder, this, "CBSCHolder::AddRef (cRefs:%ld)", lRet);
DEBUG_LEAVE(lRet);
return lRet;
}
STDMETHODIMP_(ULONG) CBSCHolder::Release(void)
{
DEBUG_ENTER((DBG_CALLBACK,
Dword,
"CBSCHolder::IUnknown::Release",
"this=%#x",
this
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::Release");
UrlMkAssert((_CRefs > 0));
LONG lRet = --_CRefs;
if (_CRefs == 0)
{
delete this;
}
PerfDbgLog1(tagCBSCHolder, this, "-CBSCHolder::Release (cRefs:%ld)",lRet);
DEBUG_LEAVE(lRet);
return lRet;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::GetBindInfo
//
// Synopsis:
//
// Arguments: [grfBINDINFOF] --
// [pbindinfo] --
//
// Returns:
//
// History:
//
// Notes: Only the first BSC which also receives data gets called
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::GetBindInfo(DWORD *grfBINDINFOF,BINDINFO * pbindinfo)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IBindStatusCallback::GetBindInfo",
"this=%#x, %#x, %#x",
this, grfBINDINFOF, pbindinfo
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::GetBindInfo");
HRESULT hr = E_FAIL;
CBSCNode *pNode;
pNode = _pCBSCNode;
if (pNode && (pNode->GetFlags() & BSCO_GETBINDINFO))
{
UrlMkAssert(( pbindinfo && (pbindinfo->cbSize == sizeof(BINDINFO)) ));
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"EXTERNAL_CLIENT::IBindStatusCallback::GetBindInfo",
"this=%#x, %#x, %#x",
pNode->GetBSCB(), grfBINDINFOF, pbindinfo
));
// We only call the first link for GetBindInfo.
hr = pNode->GetBSCB()->GetBindInfo(grfBINDINFOF, pbindinfo);
DEBUG_LEAVE(hr);
}
else
{
UrlMkAssert((FALSE && "Not IBSC node called on GetBindInfo"));
}
PerfDbgLog2(tagCBSCHolder, this, "-CBSCHolder::CallGetBindInfo (grfBINDINFOF:%lx, hr:%lx)", grfBINDINFOF, hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::OnStartBinding
//
// Synopsis:
//
// Arguments: [grfBINDINFOF] --
// [pib] --
//
// Returns:
//
// History:
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::OnStartBinding(DWORD grfBINDINFOF, IBinding * pib)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IBindStatusCallback::OnStartBinding",
"this=%#x, %#x, %#x",
this, grfBINDINFOF, pib
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::OnStartBinding");
VDATETHIS(this);
HRESULT hr = E_FAIL;
CBSCNode *pNode;
BOOL fFirstNode = TRUE;
_fBindStarted = TRUE;
pNode = _pCBSCNode;
while (pNode)
{
grfBINDINFOF = pNode->GetFlags();
if (fFirstNode)
{
grfBINDINFOF |= (BSCO_ONDATAAVAILABLE | BSCO_ONOBJECTAVAILABLE);
}
else
{
grfBINDINFOF &= ~(BSCO_ONDATAAVAILABLE | BSCO_ONOBJECTAVAILABLE);
}
DbgLog1(tagCBSCHolder, this, "CBSCHolder::OnStartBinding on (IBSC:%lx)", pNode->GetBSCB());
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"EXTERNAL_CLIENT::IBindStatusCallback::OnStartBinding",
"this=%#x, %#x, %#x",
pNode->GetBSCB(), grfBINDINFOF, pib
));
hr = pNode->GetBSCB()->OnStartBinding(grfBINDINFOF, pib);
DEBUG_LEAVE(hr);
pNode = pNode->GetNextNode();
fFirstNode = FALSE;
}
// BUGBUG: hr is set to return code only from last node we called.
// Is this what we want?
// What if one of the earlier nodes failed?
PerfDbgLog1(tagCBSCHolder, this, "-CBSCHolder::OnStartBinding (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::OnProgress
//
// Synopsis:
//
// Arguments: [ULONG] --
// [ulProgressMax] --
// [ulStatusCode] --
// [szStatusText] --
//
// Returns:
//
// History:
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::OnProgress(ULONG ulProgress,ULONG ulProgressMax,
ULONG ulStatusCode, LPCWSTR szStatusText)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IBindStatusCallback::OnProgress",
"this=%#x, %#x, %#x, %#x, %.80wq",
this, ulProgress, ulProgressMax, ulStatusCode, szStatusText
));
PerfDbgLog4(tagCBSCHolder, this, "+CBSCHolder::OnProgress (StatusCode:%ld, StatusText:%ws, Progress:%ld, ProgressMax:%ld)",
ulStatusCode, szStatusText?szStatusText:L"", ulProgress, ulProgressMax);
VDATETHIS(this);
HRESULT hr = NOERROR;
CBSCNode *pNode;
pNode = _pCBSCNode;
while (pNode)
{
if (pNode->GetFlags() & BSCO_ONPROGRESS)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"EXTERNAL_CLIENT::IBindStatusCallback::OnProgress",
"this=%#x, %#x, %#x, %#x, %.80wq",
pNode->GetBSCB(), ulProgress, ulProgressMax, ulStatusCode, szStatusText
));
hr = pNode->GetBSCB()->OnProgress(ulProgress, ulProgressMax, ulStatusCode,szStatusText);
DEBUG_LEAVE(hr);
}
pNode = pNode->GetNextNode();
}
// BUGBUG: hr is set to return code only from last node we called.
// Is this what we want?
// What if one of the earlier nodes failed?
PerfDbgLog1(tagCBSCHolder, this, "-CBSCHolder::OnProgress (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::OnDataAvailable
//
// Synopsis:
//
// Arguments: [DWORD] --
// [FORMATETC] --
// [pformatetc] --
// [pstgmed] --
//
// Returns:
//
// History:
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::OnDataAvailable(DWORD grfBSC,DWORD dwSize,FORMATETC *pformatetc, STGMEDIUM *pstgmed)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IBindStatusCallback::OnDataAvailable",
"this=%#x, %#x, %#x, %#x, %#x",
this, grfBSC, dwSize, pformatetc, pstgmed
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::OnDataAvailable");
VDATETHIS(this);
HRESULT hr = E_FAIL;
CBSCNode *pNode;
pNode = _pCBSCNode;
if (pNode && (pNode->GetFlags() & BSCO_ONDATAAVAILABLE))
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"EXTERNAL_CLIENT::IBindStatusCallback::OnDataAvailable",
"this=%#x, %#x, %#x, %#x, %#x",
pNode->GetBSCB(), grfBSC, dwSize, pformatetc, pstgmed
));
hr = pNode->GetBSCB()->OnDataAvailable(grfBSC, dwSize, pformatetc, pstgmed);
DEBUG_LEAVE(hr);
//hr = NOERROR; //Trident BTS->BTO
}
PerfDbgLog1(tagCBSCHolder, this, "-CBSCHolder::OnDataAvailable (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::OnObjectAvailable
//
// Synopsis:
//
// Arguments: [riid] --
// [punk] --
//
// Returns:
//
// History:
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::OnObjectAvailable(REFIID riid, IUnknown *punk)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IBindStatusCallback::OnObjectAvailable",
"this=%#x, %#x, %#x",
this, &riid, punk
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::OnObjectAvailable");
VDATETHIS(this);
CBSCNode *pNode;
pNode = _pCBSCNode;
if (pNode && (pNode->GetFlags() & BSCO_ONOBJECTAVAILABLE))
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"EXTERNAL_CLIENT::IBindStatusCallback::OnObjectAvailable",
"this=%#x, %#x, %#x",
pNode->GetBSCB(), &riid, punk
));
HRESULT hr = pNode->GetBSCB()->OnObjectAvailable(riid, punk);
DEBUG_LEAVE(hr);
}
PerfDbgLog(tagCBSCHolder, this, "-CBSCHolder::OnObjectAvailable (hr:0)");
DEBUG_LEAVE(NOERROR);
return NOERROR;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::OnLowResource
//
// Synopsis:
//
// Arguments: [reserved] --
//
// Returns:
//
// History:
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::OnLowResource(DWORD reserved)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IBindStatusCallback::OnLowResource",
"this=%#x, %#x",
this, reserved
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::OnLowResource");
VDATETHIS(this);
HRESULT hr = E_FAIL;
CBSCNode *pNode;
pNode = _pCBSCNode;
while (pNode)
{
if (pNode->GetFlags() & BSCO_ONLOWRESOURCE)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"EXTERNAL_CLIENT::IBindStatusCallback::OnLowResource",
"this=%#x, %#x",
pNode->GetBSCB(), reserved
));
hr = pNode->GetBSCB()->OnLowResource(reserved);
DEBUG_LEAVE(hr);
}
pNode = pNode->GetNextNode();
}
// BUGBUG: hr is set to return code only from last node we called.
// Is this what we want?
// What if one of the earlier nodes failed?
PerfDbgLog1(tagCBSCHolder, this, "-CBSCHolder::OnLowResource (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::OnStopBinding
//
// Synopsis:
//
// Arguments: [LPCWSTR] --
// [szError] --
//
// Returns:
//
// History:
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::OnStopBinding(HRESULT hrRes,LPCWSTR szError)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IBindStatusCallback::OnStopBinding",
"this=%#x, %#x, %.80wq",
this, hrRes, szError
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::OnStopBinding");
HRESULT hr = E_FAIL;
CBSCNode *pNode;
CBSCNode *pNodeNext;
DWORD dwFault;
VDATETHIS(this);
_fBindStopped = TRUE; // Allow consumer to remove node on OnStopBinding.
pNode = _pCBSCNode;
while (pNode)
{
// save the next node since this node
// we using now might get deleted
// by RevokeBindStatusCallback
pNodeNext = pNode->GetNextNode();
pNode->SetLocalFlags(NODE_FLAG_REMOVEOK);
PerfDbgLog2(tagCBSCHolder, this, "+CBSCHolder::OnStopBinding calling (Node:%lx, IBSC:%lx)",
pNode,pNode->GetBSCB());
// IE4 bug #32739, the CBSC might no longer be there (MSN)
_try
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"EXTERNAL_CLIENT::IBindStatusCallback::OnStopBinding",
"this=%#x, %#x, %.80wq",
pNode->GetBSCB(), hrRes, szError
));
hr = pNode->GetBSCB()->OnStopBinding(hrRes, szError);
DEBUG_LEAVE(hr);
}
//_except(UrlMonInvokeExceptionFilterMSN(GetExceptionCode(), GetExceptionInformation()))
__except(EXCEPTION_EXECUTE_HANDLER)
{
DEBUG_LEAVE(hr);
#if DBG == 1
{
dwFault = GetExceptionCode();
DbgLog1(tagCBSCHolder, this, "fault 0x%08x at OnStopBinding", dwFault);
}
#endif
}
#ifdef unix
__endexcept
#endif /* unix */
PerfDbgLog1(tagCBSCHolder, this, "-CBSCHolder::OnStopBinding done (Node:%lx)", pNode);
pNode = pNodeNext;
}
// Reset bind active flags.
_fBindStarted = FALSE;
_fBindStopped = FALSE;
// BUGBUG: hr is set to return code only from last node we called.
// Is this what we want?
// What if one of the earlier nodes failed?
PerfDbgLog1(tagCBSCHolder, this, "-CBSCHolder::OnStopBinding (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::GetPriority
//
// Synopsis:
//
// Arguments: [pnPriority] --
//
// Returns:
//
// History:
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::GetPriority(LONG * pnPriority)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IBindStatusCallback::GetPriority",
"this=%#x, %#x",
this, pnPriority
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::GetPriority");
HRESULT hr = E_FAIL;
CBSCNode *pNode;
pNode = _pCBSCNode;
if (pNode && (pNode->GetFlags() & BSCO_GETPRIORITY))
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"EXTERNAL_CLIENT::IBindStatusCallback::GetPriority",
"this=%#x, %#x",
pNode->GetBSCB(), pnPriority
));
hr = pNode->GetBSCB()->GetPriority(pnPriority);
DEBUG_LEAVE(hr);
}
PerfDbgLog1(tagCBSCHolder, this, "-CBSCHolder::GetPriority (hr:%lx)", hr);
DEBUG_LEAVE(S_FALSE);
return S_FALSE;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::QueryService
//
// Synopsis:
//
// Arguments: [rsid] --
// [iid] --
// [ppvObj] --
//
// Returns:
//
// History: 4-05-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::QueryService(REFGUID rsid, REFIID riid, void ** ppvObj)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IServiceProvider::QueryService",
"this=%#x, %#x, %#x, %#x",
this, &rsid, &riid, ppvObj
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::QueryService");
HRESULT hr = NOERROR;
VDATETHIS(this);
UrlMkAssert((ppvObj));
*ppvObj = 0;
hr = ObtainService(rsid, riid, ppvObj);
UrlMkAssert(( (hr == E_NOINTERFACE) || ((hr == NOERROR) && *ppvObj) ));
PerfDbgLog1(tagCBSCHolder, this, "-CBSCHolder::QueryService (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::BeginningTransaction
//
// Synopsis:
//
// Arguments: [szURL] --
// [szHeaders] --
// [dwReserved] --
// [pszAdditionalHeaders] --
//
// Returns:
//
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders,
DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IHttpNegotiate::BeginningTransaction",
"this=%#x, %.80wq, %.80wq, %#x, %#x",
this, szURL, szHeaders, dwReserved, pszAdditionalHeaders
));
PerfDbgLog2(tagCBSCHolder, this, "+CBSCHolder::BeginningTransaction (szURL:%ws, szHeaders:%ws)", szURL, XDBG(szHeaders,""));
VDATETHIS(this);
HRESULT hr = NOERROR;
CBSCNode *pNode;
LPWSTR szTmp = NULL, szNew = NULL, szRunning = NULL;
pNode = _pCBSCNode;
UrlMkAssert((szURL));
while (pNode)
{
if (pNode->GetHttpNegotiate())
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"EXTERNAL_CLIENT::IHttpNegotiate::BeginningTransaction",
"this=%#x, %.80wq, %.80wq, %#x, %#x",
pNode->GetHttpNegotiate(), szURL, szHeaders, dwReserved, pszAdditionalHeaders
));
hr = pNode->GetHttpNegotiate()->BeginningTransaction(szURL, szHeaders, dwReserved, &szNew);
DEBUG_LEAVE(hr);
PerfDbgLog2(tagCBSCHolder, this, "CBSCHolder::BeginningTransaction (IHttpNegotiate:%lx, szNew:%ws)",
pNode->GetHttpNegotiate(), XDBG(szNew,L""));
// shdocvw might return uninitialized hr, so we
// should just check for szNew not NULL and reset hr
if( hr != NOERROR && szNew != NULL )
{
hr = NOERROR;
}
if (hr == NOERROR && szNew != NULL && szRunning != NULL)
{
szTmp = szRunning;
szRunning = new WCHAR [wcslen(szTmp) + 1 + wcslen(szNew) + 1];
if (szRunning)
{
if (szTmp)
{
wcscpy(szRunning, szTmp);
wcscat(szRunning, szNew);
}
else
{
wcscpy(szRunning, szNew);
}
}
else
{
hr = E_OUTOFMEMORY;
}
delete szTmp;
delete szNew;
if (hr != NOERROR)
{
goto BegTransExit;
}
}
else
{
szRunning = szNew;
}
}
pNode = pNode->GetNextNode();
}
*pszAdditionalHeaders = szRunning;
BegTransExit:
PerfDbgLog1(tagCBSCHolder, this, "-CBSCHolder::BeginningTransaction (pszAdditionalHeaders:%ws)", (hr || !*pszAdditionalHeaders) ? L"":*pszAdditionalHeaders);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::OnResponse
//
// Synopsis:
//
// Arguments: [LPCWSTR] --
// [szResponseHeaders] --
// [LPWSTR] --
// [pszAdditionalRequestHeaders] --
//
// Returns:
//
// History: 4-05-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::OnResponse(DWORD dwResponseCode,LPCWSTR wzResponseHeaders,
LPCWSTR wzRequestHeaders,LPWSTR *pszAdditionalRequestHeaders)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IHttpNegotiate::OnResponse",
"this=%#x, %#x, %.80wq, %.80wq, %#x",
this, dwResponseCode, wzResponseHeaders, wzRequestHeaders, pszAdditionalRequestHeaders
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::OnResponse");
VDATETHIS(this);
HRESULT hr;
CBSCNode *pNode;
LPWSTR szTmp = NULL, szNew = NULL, szRunning = NULL;
pNode = _pCBSCNode;
hr = (IsStatusOk(dwResponseCode)) ? S_OK : S_FALSE;
while (pNode)
{
if (pNode->GetHttpNegotiate())
{
PerfDbgLog1(tagCBSCHolder, this, "+CBSCHolder::OnResponse on Node: %lx", pNode);
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"EXTERNAL_CLIENT::IHttpNegotiate::OnResponse",
"this=%#x, %#x, %.80wq, %.80wq, %#x",
pNode->GetHttpNegotiate(), dwResponseCode, wzResponseHeaders, wzRequestHeaders, pszAdditionalRequestHeaders
));
hr = pNode->GetHttpNegotiate()->OnResponse(dwResponseCode, wzResponseHeaders, wzRequestHeaders, &szNew);
DEBUG_LEAVE(hr);
PerfDbgLog2(tagCBSCHolder, this, "-CBSCHolder::OnResponse on Node: %lx, hr:%lx", pNode, hr);
if (hr == NOERROR && szNew != NULL && szRunning != NULL)
{
szTmp = szRunning;
szRunning = new WCHAR [wcslen(szTmp) + 1 + wcslen(szNew) + 1];
if (szRunning)
{
if (szTmp)
{
wcscpy(szRunning, szTmp);
wcscat(szRunning, szNew);
}
else
{
wcscpy(szRunning, szNew);
}
}
else
{
hr = E_OUTOFMEMORY;
}
delete szTmp;
delete szNew;
if (hr != NOERROR)
{
goto OnErrorExit;
}
}
else
{
szRunning = szNew;
}
}
pNode = pNode->GetNextNode();
}
if (pszAdditionalRequestHeaders)
{
*pszAdditionalRequestHeaders = szRunning;
}
if (hr == E_NOTIMPL)
{
hr = NOERROR;
}
OnErrorExit:
PerfDbgLog(tagCBSCHolder, this, "-CBSCHolder::OnResponse");
DEBUG_LEAVE(hr);
return hr;
}
HRESULT CBSCHolder::GetRootSecurityId(BYTE* pbSecurityId, DWORD* cbSecurityId,
DWORD_PTR dwReserved)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IHttpNegotiate2::GetRootSecurityId",
"this=%#x, %#x, %#x, %#x",
this, pbSecurityId, cbSecurityId, dwReserved
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::GetRootSecurityId");
VDATETHIS(this);
HRESULT hr = E_FAIL;
CBSCNode *pNode;
pNode = _pCBSCNode;
while (pNode)
{
if (pNode->GetHttpNegotiate2())
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"EXTERNAL_CLIENT::IHttpNegotiate2::GetRootSecurityId",
"this=%#x, %#x, %#x, %#x",
pNode->GetHttpNegotiate2(), pbSecurityId, cbSecurityId, dwReserved
));
hr = pNode->GetHttpNegotiate2()->GetRootSecurityId( pbSecurityId, cbSecurityId, dwReserved );
DEBUG_LEAVE(hr);
if (SUCCEEDED(hr))
{
break;
}
}
pNode = pNode->GetNextNode();
}
PerfDbgLog(tagCBSCHolder, this, "-CBSCHolder::Authenticate");
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::Authenticate
//
// Synopsis:
//
// Arguments: [phwnd] --
// [pszUsername] --
// [pszPassword] --
//
// Returns:
//
// History:
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::Authenticate(HWND* phwnd, LPWSTR *pszUsername,
LPWSTR *pszPassword)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::IAuthenticate::Authenticate",
"this=%#x, %#x, %#x, %#x",
this, phwnd, pszUsername, pszPassword
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::Authenticate");
VDATETHIS(this);
HRESULT hr = NOERROR;
CBSCNode *pNode;
pNode = _pCBSCNode;
while (pNode)
{
if (pNode->GetAuthenticate())
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"EXTERNAL_CLIENT::IAuthenticate::Authenticate",
"this=%#x, %#x, %#x, %#x",
pNode->GetAuthenticate(), phwnd, pszUsername, pszPassword
));
hr = pNode->GetAuthenticate()->Authenticate(phwnd, pszUsername, pszPassword);
DEBUG_LEAVE(hr);
if (hr == S_OK)
{
break;
}
}
pNode = pNode->GetNextNode();
}
PerfDbgLog(tagCBSCHolder, this, "-CBSCHolder::Authenticate");
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::AddNode
//
// Synopsis:
//
// Arguments: [pIBSC] --
// [grfFlags] --
//
// Returns:
//
// History:
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::AddNode(IBindStatusCallback *pIBSC, DWORD grfFlags)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::AddNode",
"this=%#x, %#x, %#x",
this, pIBSC, grfFlags
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::AddNode");
HRESULT hr = NOERROR;
CLock lck(_mxs);
CBSCNode *pFirstNode = _pCBSCNode;
CBSCNode *pNode;
CBSCNode *pNodeTmp;
LPVOID pvLocal = NULL;
// No new nodes allowed after binding has started.
if (_fBindStarted)
{
hr = E_FAIL;
goto AddNodeExit;
}
// Allocate memory for new pNode member.
pNode = new CBSCNode(pIBSC, grfFlags);
if (!pNode)
{
hr = E_OUTOFMEMORY;
}
else
{
// addref the IBSC pointer
pIBSC->AddRef();
// QI for IServiceProvider - QI addref IBSC
if (pIBSC->QueryInterface(IID_IServiceProvider, &pvLocal) == NOERROR)
{
pNode->SetServiceProvider((IServiceProvider *)pvLocal);
}
PerfDbgLog3(tagCBSCHolder, this, "CBSCHolder::AddNode (New Node:%lx, IBSC:%lx, IServiceProvider:%lx)",
pNode, pNode->GetBSCB(), pvLocal);
// If we have a node already
if (pFirstNode)
{
if (pNode->GetFlags() & BSCO_ONDATAAVAILABLE)
{
// If the new node gets the data, link it first.
pNode->SetNextNode(pFirstNode);
_pCBSCNode = pNode;
}
else
{
// The new node does not get data, link it second in list.
pNodeTmp = pFirstNode->GetNextNode();
pFirstNode->SetNextNode(pNode);
pNode->SetNextNode(pNodeTmp);
}
}
else
{
_pCBSCNode = pNode;
}
_cElements++;
}
AddNodeExit:
PerfDbgLog2(tagCBSCHolder, this, "-CBSCHolder::AddNode (NewNode:%lx, hr:%lx)", pNode, hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::RemoveNode
//
// Synopsis:
//
// Arguments: [pIBSC] --
//
// Returns:
//
// History:
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::RemoveNode(IBindStatusCallback *pIBSC)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::RemoveNode",
"this=%#x, %#x",
this, pIBSC
));
PerfDbgLog1(tagCBSCHolder, this, "+CBSCHolder::RemoveNode (IBSC:%lx)", pIBSC);
HRESULT hr = E_FAIL;
CLock lck(_mxs);
CBSCNode *pNextNode = NULL;
CBSCNode *pPrevNode = _pCBSCNode;
// If binding has started, removal of nodes not allowed until binding stops.
if (_fBindStarted && !_fBindStopped)
{
UrlMkAssert((FALSE && "IBSC in use - can not be revoked"));
goto RemoveNodeExit;
}
if (pPrevNode)
{
pNextNode = pPrevNode->GetNextNode();
}
else
{
TransAssert((_cElements == 0));
hr = S_FALSE;
goto RemoveNodeExit;
}
if (_pCBSCNode->GetBSCB() == pIBSC)
{
UrlMkAssert((_pCBSCNode->GetBSCB() == pIBSC));
if (!_fBindStarted || _pCBSCNode->CheckLocalFlags(NODE_FLAG_REMOVEOK))
{
PerfDbgLog2(tagCBSCHolder, this, "CBSCHolder::RemoveNode (Delete Node:%lx, IBSC:%lx)",
_pCBSCNode, _pCBSCNode->GetBSCB());
// release all obtained objects in the disdructor
delete _pCBSCNode;
_pCBSCNode = pNextNode;
_cElements--;
if (_cElements == 0)
{
hr = S_FALSE;
}
else
{
hr = S_OK;
}
}
}
else while (pNextNode)
{
PerfDbgLog2(tagCBSCHolder, this, "CBSCHolder::RemoveNode (pNextNode:%lx, pNextNode->pIBSC:%lx)",pNextNode,pNextNode->GetBSCB());
if (pNextNode->GetBSCB() == pIBSC && (!_fBindStarted || pNextNode->CheckLocalFlags(NODE_FLAG_REMOVEOK)))
{
//we found the Node
if (pPrevNode)
{
pPrevNode->SetNextNode(pNextNode->GetNextNode());
}
PerfDbgLog2(tagCBSCHolder, this, "CBSCHolder::RemoveNode (Delete Node:%lx, IBSC:%lx)",
pNextNode,pNextNode->GetBSCB());
// release all obtained objects in the disdructor
delete pNextNode;
hr = S_OK;
_cElements--;
UrlMkAssert((_cElements > 0));
break;
}
else
{
pPrevNode = pNextNode;
pNextNode = pNextNode->GetNextNode();
}
UrlMkAssert((hr == S_OK && "Node not found"));
}
RemoveNodeExit:
PerfDbgLog1(tagCBSCHolder, this, "-CBSCHolder::RemoveNode (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::SetMainNode
//
// Synopsis:
//
// Arguments: [pIBSC] --
// [ppIBSCPrev] --
//
// Returns:
//
// History: 5-08-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::SetMainNode(IBindStatusCallback *pIBSC, IBindStatusCallback **ppIBSCPrev)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::SetMainNode",
"this=%#x, %#x, #x",
this, pIBSC, ppIBSCPrev
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::SetMainNode");
HRESULT hr = NOERROR;
CLock lck(_mxs);
CBSCNode *pFirstNode = _pCBSCNode;
CBSCNode *pNode;
CBSCNode *pNodeTmp;
LPVOID pvLocal = NULL;
// No new nodes allowed after binding has started.
if (_fBindStarted)
{
hr = E_FAIL;
goto GetFirsNodeExit;
}
if (pFirstNode)
{
IBindStatusCallback *pBSC = pFirstNode->GetBSCB();
// addref the node here and return it
if (ppIBSCPrev)
{
pBSC->AddRef();
*ppIBSCPrev = pBSC;
}
hr = RemoveNode(pBSC);
}
pFirstNode = _pCBSCNode;
// Allocate memory for new pNode member.
pNode = new CBSCNode(pIBSC, BSCO_ALLONIBSC);
if (!pNode)
{
hr = E_OUTOFMEMORY;
}
else
{
// addref the IBSC pointer
pIBSC->AddRef();
hr = NOERROR;
// QI for IServiceProvider - QI addref IBSC
if (pIBSC->QueryInterface(IID_IServiceProvider, &pvLocal) == NOERROR)
{
pNode->SetServiceProvider((IServiceProvider *)pvLocal);
}
PerfDbgLog3(tagCBSCHolder, this, "CBSCHolder::SetMainNode (New Node:%lx, IBSC:%lx, IServiceProvider:%lx)",
pNode, pNode->GetBSCB(), pvLocal);
// If we have a node already
if (pFirstNode)
{
if (pNode->GetFlags() & BSCO_ONDATAAVAILABLE)
{
// If the new node gets the data, link it first.
pNode->SetNextNode(pFirstNode);
_pCBSCNode = pNode;
}
else
{
// The new node does not get data, link it second in list.
pNodeTmp = pFirstNode->GetNextNode();
pFirstNode->SetNextNode(pNode);
pNode->SetNextNode(pNodeTmp);
}
}
else
{
_pCBSCNode = pNode;
}
_cElements++;
}
GetFirsNodeExit:
PerfDbgLog2(tagCBSCHolder, this, "-CBSCHolder::SetMainNode (NewNode:%lx, hr:%lx)", pNode, hr);
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CBSCHolder::ObtainService
//
// Synopsis: Retrieves the requested service with QI and QueryService
// for all nodes. The interfaces is addref'd and kept in the node.
//
// Arguments: [rsid] --
// [riid] --
//
// Returns:
//
// History: 4-09-96 JohannP (Johann Posch) Created
//
// Notes: The obtained interfaces are released in the disdructor of the
// CNode.
//
//----------------------------------------------------------------------------
HRESULT CBSCHolder::ObtainService(REFGUID rsid, REFIID riid, void ** ppvObj)
{
DEBUG_ENTER((DBG_CALLBACK,
Hresult,
"CBSCHolder::ObtainService",
"this=%#x, %#x, #x, %#x",
this, &rsid, &riid, ppvObj
));
PerfDbgLog(tagCBSCHolder, this, "+CBSCHolder::ObtainService");
HRESULT hr = NOERROR;
CBSCNode *pNode;
VDATETHIS(this);
LPVOID pvLocal = NULL;
pNode = _pCBSCNode;
// the old code was under the assumption that rsid was always the same
// as riid. it checked riid when it should have been checking rsid, and it
// always passed riid on in the place of rsid! All callers that I've
// seen that use IID_IHttpNegotiate and IID_IAuthenticate pass the
// same iid in both rsid and riid, so fixing this should be safe.
if (rsid == IID_IHttpNegotiate)
{
*ppvObj = (void*)(IHttpNegotiate *) this;
AddRef();
// loop once to get all interfaces
if (!_fHttpNegotiate)
{
while (pNode)
{
if ( (pNode->GetBSCB()->QueryInterface(riid, &pvLocal) == NOERROR)
|| ( pNode->GetServiceProvider()
&& (pNode->GetHttpNegotiate() == NULL)
&& (pNode->GetServiceProvider()->QueryService(rsid, riid, &pvLocal)) == NOERROR)
)
{
// Note: the interface is addref'd by QI or QS
pNode->SetHttpNegotiate((IHttpNegotiate *)pvLocal);
}
pNode = pNode->GetNextNode();
}
_fHttpNegotiate = TRUE;
}
}
else if (rsid == IID_IAuthenticate)
{
*ppvObj = (void*)(IAuthenticate *) this;
AddRef();
if (!_fAuthenticate)
{
while (pNode)
{
if ( (pNode->GetBSCB()->QueryInterface(riid, &pvLocal) == NOERROR)
|| ( pNode->GetServiceProvider()
&& (pNode->GetAuthenticate() == NULL)
&& (pNode->GetServiceProvider()->QueryService(rsid, riid, &pvLocal)) == NOERROR)
)
{
// Note: the interface is addref'd by QI or QS
pNode->SetAuthenticate((IAuthenticate *)pvLocal);
}
pNode = pNode->GetNextNode();
}
_fAuthenticate = TRUE;
}
}
else if (rsid == IID_IHttpNegotiate2)
{
*ppvObj = (void*)(IHttpNegotiate2 *) this;
AddRef();
// loop once to get all interfaces
if (!_fHttpNegotiate2)
{
while (pNode)
{
if ( (pNode->GetBSCB()->QueryInterface(riid, &pvLocal) == NOERROR)
|| ( pNode->GetServiceProvider()
&& (pNode->GetHttpNegotiate2() == NULL)
&& (pNode->GetServiceProvider()->QueryService(rsid, riid, &pvLocal)) == NOERROR)
)
{
// Note: the interface is addref'd by QI or QS
pNode->SetHttpNegotiate2((IHttpNegotiate2 *)pvLocal);
}
pNode = pNode->GetNextNode();
}
_fHttpNegotiate2 = TRUE;
}
}
else
{
*ppvObj = NULL;
hr = E_NOINTERFACE;
while (pNode)
{
// old urlmon code did a QueryInterface on this object (CBSCHolder)
// without regard to rsid. That's QueryService badness, but CINet
// (and several other places) call QueryService using the same rsid/riid
// (in this case IID_IHttpSecurity) and *expect* the below QI to pick
// the interface off the BSCB. We should create an URLMON service id
// that means "ask the BSCB for this interface" and use that...
if ( (pNode->GetBSCB()->QueryInterface(riid, &pvLocal) == NOERROR)
|| (pNode->GetServiceProvider()
&& (pNode->GetServiceProvider()->QueryService(rsid, riid, &pvLocal)) == NOERROR)
)
{
*ppvObj = pvLocal;
hr = NOERROR;
// Note: the interface is addref'd by QI or QS
// stop looking at other nodes for this service
pNode = NULL;
}
if (pNode)
{
pNode = pNode->GetNextNode();
}
}
}
PerfDbgLog1(tagCBSCHolder, this, "-CBSCHolder::ObtainService (hr:%lx)", hr);
DEBUG_LEAVE(hr);
return hr;
}