//+--------------------------------------------------------------------------- // // 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 #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; }