#include "priv.h" #include "iehelpid.h" #include "bindcb.h" #include "winlist.h" #include "droptgt.h" #include // CLSID_HTMLDocument #include "resource.h" #include #include #include #include #include "shdocfl.h" #include "interned.h" // IHTMLPrivateWindow #ifdef FEATURE_PICS #include #include #endif #include "dochost.h" #include #define THISCLASS CDocObjectHost #define SUPERCLASS CDocHostUIHandler #define BSCMSG(psz, i, j) TraceMsg(TF_SHDBINDING, "shd TR-BSC::%s %x %x", psz, i, j) #define BSCMSG3(psz, i, j, k) TraceMsg(0, "shd TR-BSC::%s %x %x %x", psz, i, j, k) #define BSCMSG4(psz, i, j, k, l) TraceMsg(0, "shd TR-BSC::%s %x %x %x %x", psz, i, j, k, l) #define BSCMSGS(psz, sz) TraceMsg(0, "shd TR-BSC::%s %s", psz, sz) #define CHAINMSG(psz, x) TraceMsg(0, "shd CHAIN::%s %x", psz, x) #define PERFMSG(psz, x) TraceMsg(TF_SHDPERF, "PERF::%s %d msec", psz, x) #define OPENMSG(psz) TraceMsg(TF_SHDBINDING, "shd OPENING %s", psz) #define DM_DOCCP 0 #define DM_DEBUGTFRAME 0 #define DM_SELFASC TF_SHDBINDING #define DM_SSL 0 #define DM_PICS 0 #define DO_SEARCH_ON_STATUSCODE(x) ((x == 0) || (x == HTTP_STATUS_BAD_GATEWAY) || (x == HTTP_STATUS_GATEWAY_TIMEOUT)) const static c_aidRes[] = { IDI_STATE_NORMAL, // 0 IDI_STATE_FINDINGRESOURCE, // BINDSTATUS_FINDINGRESOURCE IDI_STATE_FINDINGRESOURCE, // BINDSTATUS_CONNECTING IDI_STATE_FINDINGRESOURCE, // BINDSTATUS_REDIRECTING IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_BEGINDOWNLOADDATA IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_DOWNLOADINGDATA IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_ENDDOWNLOADDATA IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_BEGINDOWNLOADCOMPONENTS IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_INSTALLINGCOMPONENTS IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_ENDDOWNLOADCOMPONENTS IDI_STATE_SENDINGREQUEST, // BINDSTATUS_USINGCACHEDCOPY IDI_STATE_SENDINGREQUEST, // BINDSTATUS_SENDINGREQUEST IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_CLASSIDAVAILABLE }; extern HICON g_ahiconState[IDI_STATE_LAST-IDI_STATE_FIRST+1]; #define SEARCHPREFIX L"? " #define SEARCHPREFIXSIZE sizeof(SEARCHPREFIX) #define SEARCHPREFIXLENGTH 2 // Put the most common errors first in c_aErrorUrls. // //======================================================== // // WARNING - Thinking of changing the Table ? // // You also need to update the IsErrorHandled in mshtml // src\site\download\dwnbind.cxx // //======================================================== ErrorUrls c_aErrorUrls[] = { {404, TEXT("http_404.htm")}, {ERRORPAGE_DNS, TEXT("dnserror.htm")}, {ERRORPAGE_NAVCANCEL, TEXT("navcancl.htm")}, {ERRORPAGE_SYNTAX, TEXT("syntax.htm")}, {400, TEXT("http_400.htm")}, {403, TEXT("http_403.htm")}, {405, TEXT("http_gen.htm")}, {406, TEXT("http_406.htm")}, {408, TEXT("servbusy.htm")}, {409, TEXT("servbusy.htm")}, {410, TEXT("http_410.htm")}, {500, TEXT("http_500.htm")}, {501, TEXT("http_501.htm")}, {505, TEXT("http_501.htm")}, {ERRORPAGE_OFFCANCEL, TEXT("offcancl.htm")}, {ERRORPAGE_CHANNELNOTINCACHE, TEXT("cacheerr.htm")}, }; // // Determine if there is an internal error page for the given http error. // BOOL IsErrorHandled(DWORD dwError) { BOOL fRet = FALSE; for (int i = 0; i < ARRAYSIZE(c_aErrorUrls); i++) { if (dwError == c_aErrorUrls[i].dwError) { fRet = TRUE; break; } } return fRet; } const SA_BSTRGUID s_sstrSearchIndex = { 38 * SIZEOF(WCHAR), L"{265b75c0-4158-11d0-90f6-00c04fd497ea}" }; //extern const SA_BSTRGUID s_sstrSearchFlags; const SA_BSTRGUID s_sstrSearchFlags = { 38 * SIZEOF(WCHAR), L"{265b75c1-4158-11d0-90f6-00c04fd497ea}" }; EXTERN_C const SA_BSTRGUID s_sstrSearch = { 38 * SIZEOF(WCHAR), L"{118D6040-8494-11d2-BBFE-0060977B464C}" }; EXTERN_C const SA_BSTRGUID s_sstrFailureUrl = { 38 * SIZEOF(WCHAR), L"{04AED800-8494-11d2-BBFE-0060977B464C}" }; // // Clears that parameters set by window.external.AutoScan() // HRESULT _ClearSearchString(IServiceProvider* psp) { HRESULT hr = E_FAIL; if (psp == NULL) return hr; IWebBrowser2 *pWB2 = NULL; hr = psp->QueryService(SID_SHlinkFrame, IID_IWebBrowser2, (LPVOID*)&pWB2); if (pWB2 && SUCCEEDED(hr)) { VARIANT v; VariantInit(&v); v.vt = VT_EMPTY; hr = pWB2->PutProperty((BSTR)s_sstrSearch.wsz, v); hr = pWB2->PutProperty((BSTR)s_sstrFailureUrl.wsz, v); pWB2->Release(); } return hr; } // // Gets the string that was entered in the addressbar // HRESULT _GetSearchString(IServiceProvider* psp, VARIANT* pvarSearch) { HRESULT hr = E_FAIL; if (psp != NULL) { VariantInit(pvarSearch); IDockingWindow* psct = NULL; IOleCommandTarget* poct; // first see if there is an ISearchContext to get this information from ISearchContext * pSC = NULL; hr = psp->QueryService(SID_STopWindow, IID_ISearchContext, (void **) &pSC); if (SUCCEEDED(hr)) { RIP(pSC != NULL); pvarSearch->vt = VT_BSTR; hr = pSC->GetSearchText(&(pvarSearch->bstrVal)); pSC->Release(); } else { // otherwise try to get the search string directly out of the address bar hr = psp->QueryService(SID_SExplorerToolbar, IID_IDockingWindow, (LPVOID*)&psct); if (SUCCEEDED(hr)) { hr = psct->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&poct); if (SUCCEEDED(hr)) { // NULL is the first parameter so our ErrorMsgBox // doesn't call EnableModelessSB() // If we don't, our pdoh members may be freed // by the time we return. hr = poct->Exec(&CGID_Explorer, SBCMDID_GETUSERADDRESSBARTEXT, 0, NULL, pvarSearch); poct->Release(); } psct->Release(); } } } return hr; } // // Get page that should be displayed if the AutoScan fails // HRESULT _GetScanFailureUrl(IServiceProvider* psp, VARIANT* pvarFailureUrl) { HRESULT hr = E_FAIL; if (psp == NULL) return hr; // // See if a default failure page is stored as a property of the page // IWebBrowser2 *pWB2 = NULL; hr = psp->QueryService(SID_SHlinkFrame, IID_IWebBrowser2, (LPVOID*)&pWB2); if (pWB2 && SUCCEEDED(hr)) { hr = pWB2->GetProperty((BSTR)s_sstrFailureUrl.wsz, pvarFailureUrl); pWB2->Release(); } return hr; } HRESULT _GetSearchInfo(IServiceProvider *psp, LPDWORD pdwIndex, LPBOOL pfAllowSearch, LPBOOL pfContinueSearch, LPBOOL pfSentToEngine, VARIANT* pvarUrl) { HRESULT hr = E_FAIL; DWORD dwFlags = 0; if (psp) { IWebBrowser2 *pWB2 = NULL; hr = psp->QueryService(SID_SHlinkFrame, IID_IWebBrowser2, (LPVOID*)&pWB2); if (pWB2 && SUCCEEDED(hr)) { if (pdwIndex) { VARIANT v; if (SUCCEEDED(pWB2->GetProperty((BSTR)s_sstrSearchIndex.wsz, &v))) { if (v.vt == VT_I4) *pdwIndex = v.lVal; VariantClear(&v); } } if (pfAllowSearch || pfContinueSearch || pfSentToEngine) { VARIANT v; if (SUCCEEDED(pWB2->GetProperty((BSTR)s_sstrSearchFlags.wsz, &v))) { if (v.vt == VT_I4) dwFlags = v.lVal; VariantClear(&v); } } // // If we have a search string property, and the index is zero, we start // with the second autoscan index. This is because the first index should // have already been tried (see window.external.AutoScan()). // if (pvarUrl) { VariantInit(pvarUrl); // in case of failure if (SUCCEEDED(pWB2->GetProperty((BSTR)s_sstrSearch.wsz, pvarUrl)) && pvarUrl->vt == VT_BSTR && pdwIndex && *pdwIndex == 0) { *pdwIndex = 2; } } if (pfAllowSearch) *pfAllowSearch = ((dwFlags & 0x01) ? TRUE : FALSE); if (pfContinueSearch) *pfContinueSearch = ((dwFlags & 0x02) ? TRUE : FALSE); if (pfSentToEngine) *pfSentToEngine = ((dwFlags & 0x04) ? TRUE : FALSE); pWB2->Release(); } } return hr; } HRESULT CDocObjectHost::CDOHBindStatusCallback::_SetSearchInfo(CDocObjectHost *pdoh, DWORD dwIndex, BOOL fAllowSearch, BOOL fContinueSearch, BOOL fSentToEngine) { HRESULT hr = E_FAIL; DWORD dwFlags = 0; dwFlags = (fAllowSearch ? 0x01 : 0) + (fContinueSearch ? 0x02 : 0) + (fSentToEngine ? 0x04 : 0); if (pdoh->_psp) { IWebBrowser2 *pWB2 = NULL; hr = pdoh->_psp->QueryService(SID_SHlinkFrame, IID_IWebBrowser2, (LPVOID*)&pWB2); if (pWB2 && SUCCEEDED(hr)) { VARIANT v; VariantInit (&v); v.vt = VT_I4; v.lVal = dwIndex; pWB2->PutProperty((BSTR)s_sstrSearchIndex.wsz, v); v.vt = VT_I4; v.lVal = dwFlags; pWB2->PutProperty((BSTR)s_sstrSearchFlags.wsz, v); pWB2->Release(); } } // If we are done, clear any parameters set by window.external.AutoScan(). if (!fContinueSearch) { _ClearSearchString(pdoh->_psp); } TraceMsg(TF_SHDNAVIGATE, "::HFNS_SetSearchInfo() hr = %X, index = %d, allow = %d, cont = %d, sent = %d", hr, dwIndex, fAllowSearch, fContinueSearch, fSentToEngine); return hr; } // // Gets the prefix/postfix to use for autoscanning (www.%s.com, etc) // LONG GetSearchFormatString(DWORD dwIndex, LPTSTR psz, DWORD cbpsz) { TCHAR szValue[11]; //Should be large enough to hold max dword 4294967295 DWORD dwType; wnsprintf(szValue, ARRAYSIZE(szValue), TEXT("%d"), dwIndex); return SHRegGetUSValue(REGSTR_PATH_SEARCHSTRINGS, szValue, &dwType, (LPVOID)psz, &cbpsz, FALSE, NULL, 0); } // dwSearchForExtensions : 0 do not search // dwSearchForExtensions : 1 search through list of exts. // dwSearchForExtensions : 2 move on to autosearch // 0 = never ask, never search // 1 = always ask // 2 = never ask, always search HRESULT GetSearchKeys(IServiceProvider * psp, LPDWORD pdwSearchStyle, LPDWORD pdwSearchForExtensions, LPDWORD pdwDo404Search) { RIP(pdwSearchStyle != NULL); RIP(pdwSearchForExtensions != NULL); RIP(pdwDo404Search != NULL); GetSearchStyle(psp, pdwSearchStyle); if (*pdwSearchStyle == 0) { *pdwSearchForExtensions = NO_SUFFIXES; *pdwDo404Search = NEVERSEARCH; } else { *pdwSearchForExtensions = SCAN_SUFFIXES; *pdwDo404Search = ALWAYSSEARCH; } return S_OK; } // GetSearchKeys // // Map error codes to error urls. // int EUIndexFromError(DWORD dwError) { for (int i = 0; i < ARRAYSIZE(c_aErrorUrls); i++) { if (dwError == c_aErrorUrls[i].dwError) break; } ASSERT(i < ARRAYSIZE(c_aErrorUrls)); return i; } // // IsErrorUrl determines if the given url is an internal error page url. // BOOL IsErrorUrl(LPCWSTR pwszDisplayName) { BOOL fRet = FALSE; TCHAR szDisplayName[MAX_URL_STRING]; UnicodeToTChar(pwszDisplayName, szDisplayName, ARRAYSIZE(szDisplayName)); // // First check if the prefix matches. // if (0 == StrCmpN(szDisplayName, TEXT("res://"), 6)) { int iResStart; // find the resource name part of the URL // use the fact that the DLL path will be using // '\' as delimiters while the URL in general // uses '/' iResStart = 6; while (szDisplayName[iResStart] != TEXT('/')) { if (szDisplayName[iResStart] == TEXT('\0')) return fRet; iResStart++; } iResStart++; // get off the '/' // // Check each url in order. // for (int i = 0; i < ARRAYSIZE(c_aErrorUrls); i++) { if (0 == StrCmpN(szDisplayName + iResStart, c_aErrorUrls[i].pszUrl, lstrlen(c_aErrorUrls[i].pszUrl))) { fRet = TRUE; break; } } } return fRet; } // // When an http error occurs the server generally returns a page. The // threshold value this function returns is used to determine if the // server page is displayed (if the size of the returned page is greater than // the threshold) or if an internal error page is shown (if the returned page // is smaller than the threshold). // DWORD _GetErrorThreshold(DWORD dwError) { DWORD dwRet; TCHAR szValue[11]; //Should be large enough to hold max dword 4294967295 DWORD cbValue = ARRAYSIZE(szValue); DWORD cbdwRet = sizeof(dwRet); DWORD dwType = REG_DWORD; wnsprintf(szValue, ARRAYSIZE(szValue), TEXT("%d"), dwError); if (ERROR_SUCCESS != SHRegGetUSValue(REGSTR_PATH_THRESHOLDS, szValue, &dwType, (LPVOID)&dwRet, &cbdwRet, FALSE, NULL, 0)) { dwRet = 512; // hard coded default size if all else fails. } return dwRet; } void CDocObjectHost::CDOHBindStatusCallback::_RegisterObjectParam(IBindCtx* pbc) { // pbc->RegisterObjectParam(L"BindStatusCallback", this); _fAborted = FALSE; HRESULT hres = RegisterBindStatusCallback(pbc, this, 0, 0); BSCMSG3(TEXT("_RegisterObjectParam returned"), hres, this, pbc); } void CDocObjectHost::CDOHBindStatusCallback::_RevokeObjectParam(IBindCtx* pbc) { // pbc->RevokeObjectParam(L"BindStatusCallback"); HRESULT hres = RevokeBindStatusCallback(pbc, this); AssertMsg(SUCCEEDED(hres), TEXT("URLMON bug??? RevokeBindStatusCallback failed %x"), hres); BSCMSG3(TEXT("_RevokeObjectParam returned"), hres, this, pbc); } CDocObjectHost::CDOHBindStatusCallback::~CDOHBindStatusCallback() { TraceMsg(DM_DEBUGTFRAME, "dtor CDocObjectHost::CBSC %x", this); if (_pib) { AssertMsg(0, TEXT("CBSC::~ _pib is %x (this=%x)"), _pib, this); } ATOMICRELEASE(_pib); if (_pbc) { AssertMsg(0, TEXT("CBSC::~ _pbc is %x (this=%x)"), _pbc, this); } ATOMICRELEASE(_pbc); if (_psvPrev) { AssertMsg(0, TEXT("CBSC::~ _psvPrev is %x (this=%x)"), _psvPrev, this); } ATOMICRELEASE(_psvPrev); ATOMICRELEASE(_pbscChained); ATOMICRELEASE(_pnegotiateChained); if (_hszPostData) { GlobalFree(_hszPostData); _hszPostData = NULL; } if (_pszHeaders) { LocalFree(_pszHeaders); _pszHeaders = NULL; } if (_pszRedirectedURL) { LocalFree(_pszRedirectedURL); _pszRedirectedURL = NULL; } if(_pszCacheFileName) { LocalFree(_pszCacheFileName); _pszCacheFileName = NULL; } if (_pszPolicyRefURL) { LocalFree(_pszPolicyRefURL); _pszPolicyRefURL = NULL; } if (_pszP3PHeader) { LocalFree(_pszP3PHeader); _pszP3PHeader = NULL; } } HRESULT CDocObjectHost::CDOHBindStatusCallback::QueryInterface(REFIID riid, LPVOID * ppvObj) { if (IsEqualIID(riid, IID_IBindStatusCallback) || IsEqualIID(riid, IID_IUnknown)) { *ppvObj = SAFECAST(this, IBindStatusCallback*); } else if (IsEqualIID(riid, IID_IHttpNegotiate)) { *ppvObj = SAFECAST(this, IHttpNegotiate*); } else if (IsEqualIID(riid, IID_IAuthenticate)) { *ppvObj = SAFECAST(this, IAuthenticate*); } else if (IsEqualIID(riid, IID_IServiceProvider)) { *ppvObj = SAFECAST(this, IServiceProvider*); } else if (IsEqualIID(riid, IID_IHttpSecurity)) { *ppvObj = SAFECAST(this, IHttpSecurity*); } else if (IsEqualIID(riid, IID_IWindowForBindingUI)) { *ppvObj = SAFECAST(this, IWindowForBindingUI*); } else { *ppvObj = NULL; return E_NOINTERFACE; } AddRef(); return NOERROR; } ULONG CDocObjectHost::CDOHBindStatusCallback::AddRef(void) { CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this); return pdoh->AddRef(); } ULONG CDocObjectHost::CDOHBindStatusCallback::Release(void) { CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this); return pdoh->Release(); } void SetBindfFlagsBasedOnAmbient(BOOL fAmbientOffline, DWORD *grfBindf); #define CP_UCS_2 1200 // Unicode, ISO 10646 #define CP_UCS_2_BIGENDIAN 1201 // Unicode #define CP_UTF_8 65001 UINT NavigatableCodePage(UINT cp) { return (cp == CP_UCS_2 || cp == CP_UCS_2_BIGENDIAN) ? CP_UTF_8 : cp; } HRESULT CDocObjectHost::CDOHBindStatusCallback::GetBindInfo( DWORD* grfBINDF, BINDINFO *pbindinfo) { if ( !grfBINDF || !pbindinfo || !pbindinfo->cbSize ) return E_INVALIDARG; DWORD dwConnectedStateFlags = 0; CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this); BSCMSG(TEXT("GetBindInfo"), 0, 0); *grfBINDF = BINDF_ASYNCHRONOUS; // Delegation is valid ONLY for the ::GetBindInfo() method if (_pbscChained) { CHAINMSG("GetBindInfo", grfBINDF); _pbscChained->GetBindInfo(grfBINDF, pbindinfo); DWORD dwFlags = 0; if (pdoh->_pwb) { pdoh->_pwb->GetFlags(&dwFlags); } pbindinfo->dwCodePage = (dwFlags & BSF_SETNAVIGATABLECODEPAGE) ? NavigatableCodePage(pdoh->_uiCP) : pdoh->_uiCP; // As far as offline mode is concerned, we want the latest // info. Over-rule what the delegated IBSC returned SetBindfFlagsBasedOnAmbient(_bFrameIsOffline, grfBINDF); if(_bFrameIsSilent) *grfBINDF |= BINDF_NO_UI; else *grfBINDF &= ~BINDF_NO_UI; } else { // fill out the BINDINFO struct *grfBINDF = 0; BuildBindInfo(grfBINDF,pbindinfo,_hszPostData,_cbPostData, _bFrameIsOffline, _bFrameIsSilent, FALSE, /* bHyperlink */ (IBindStatusCallback *) this); // HTTP headers are added by the callback to our // IHttpNegotiate::BeginningTransaction() method } // Remember it to perform modeless download for POST case. _dwBindVerb = pbindinfo->dwBindVerb; // Remember this to use when populating the threadparams for CDownload. // (FerhanE): We are only remembering the restricted zone enforcement // to not break anything that depended on other flags being // not set before. _dwBindf = *grfBINDF & BINDF_ENFORCERESTRICTED; return S_OK; } // *** IAuthenticate *** HRESULT CDocObjectHost::CDOHBindStatusCallback::Authenticate( HWND *phwnd, LPWSTR *pszUsername, LPWSTR *pszPassword) { CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this); if (!phwnd || !pszUsername || !pszPassword) return E_POINTER; if(!_bFrameIsSilent){ if (pdoh->_psb) { pdoh->_psb->GetWindow(phwnd); } else { *phwnd = pdoh->_hwnd; } }else{ *phwnd = NULL; } *pszUsername = NULL; *pszPassword = NULL; // If we're a frame in the active desktop, then find out // the user name and password are stored with the subscription // and use it if(_IsDesktopItem(pdoh)) { // Get the URL LPOLESTR pszURL; HRESULT hres; hres = pdoh->_GetCurrentPageW(&pszURL, TRUE); if(SUCCEEDED(hres)) { IActiveDesktop *pActiveDesk; hres = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER, IID_IActiveDesktop, (LPVOID*)&pActiveDesk); if(SUCCEEDED(hres)) { // Get the subscribed URL for this COMPONENT Component; Component.dwSize = SIZEOF(Component); Component.wszSubscribedURL[0] = TEXT('\0'); hres = pActiveDesk->GetDesktopItemBySource(pszURL, &Component, 0); if(SUCCEEDED(hres) && Component.wszSubscribedURL[0]) { // We have a non null subscribed URL // Gotta find the user name and password // associated with this subscription ISubscriptionMgr *pSubsMgr; hres = CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr, (LPVOID*)&pSubsMgr); if(SUCCEEDED(hres)) { SUBSCRIPTIONINFO SubInfo; SubInfo.cbSize = sizeof(SUBSCRIPTIONINFO); SubInfo.fUpdateFlags = (SUBSINFO_NEEDPASSWORD | SUBSINFO_TYPE | SUBSINFO_USER | SUBSINFO_PASSWORD); SubInfo.bstrUserName = NULL; SubInfo.bstrPassword = NULL; hres = pSubsMgr->GetSubscriptionInfo(Component.wszSubscribedURL, &SubInfo); if(SUCCEEDED(hres) && SubInfo.bNeedPassword) { if((SubInfo.bstrUserName) && (SubInfo.bstrPassword)) { // Copy user name and password SHStrDupW(SubInfo.bstrPassword, pszPassword); SHStrDupW(SubInfo.bstrUserName, pszUsername); } } if(SubInfo.bstrPassword) SysFreeString(SubInfo.bstrPassword); if(SubInfo.bstrUserName) SysFreeString(SubInfo.bstrUserName); pSubsMgr->Release(); } } pActiveDesk->Release(); } OleFree(pszURL); } } return S_OK; } // *** IServiceProvider *** HRESULT CDocObjectHost::CDOHBindStatusCallback::QueryService(REFGUID guidService, REFIID riid, void **ppvObj) { HRESULT hres = E_FAIL; *ppvObj = NULL; if (IsEqualGUID(guidService, IID_IAuthenticate)) { return QueryInterface(riid, ppvObj); } else if (IsEqualGUID(guidService, IID_ITargetFrame2)) { return IToClass(CDocObjectHost, _bsc, this)->QueryService( guidService, riid, ppvObj); } else if (_pbscChained) { // Has a delegating IBindStatusCallback. IServiceProvider* psp; hres = _pbscChained->QueryInterface(IID_IServiceProvider, (LPVOID*)&psp); if (SUCCEEDED(hres)) { // It supports ServiceProvider, just delegate. hres = psp->QueryService(guidService, riid, ppvObj); psp->Release(); } else if (IsEqualGUID(guidService, riid)) { // It does not supports ServiceProvide, try QI. hres = _pbscChained->QueryInterface(riid, ppvObj); } } return hres; } HRESULT CDocObjectHost::CDOHBindStatusCallback::OnStartBinding( DWORD grfBSCOption, IBinding *pib) { BSCMSG(TEXT("OnStartBinding"), _pib, pib); CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this); _fBinding = TRUE; _fDocWriteAbort = FALSE; _fBoundToMSHTML = FALSE; ASSERT(pdoh->_pocthf); // ASSERT(_pib==NULL); ATOMICRELEASE(_pib); _pib = pib; if (_pib) { _pib->AddRef(); } #ifndef NO_DELEGATION if (_pbscChained) { CHAINMSG("OnStartBinding", grfBSCOption); _pbscChained->OnStartBinding(grfBSCOption, pib); } #endif pdoh->_fShowProgressCtl = TRUE; pdoh->_PlaceProgressBar(TRUE); _privacyQueue.Reset(); ResetPrivacyInfo(); return S_OK; } HRESULT CDocObjectHost::CDOHBindStatusCallback::GetPriority(LONG *pnPriority) { BSCMSG(TEXT("GetPriority"), 0, 0); *pnPriority = NORMAL_PRIORITY_CLASS; #ifndef NO_DELEGATION if (_pbscChained) { _pbscChained->GetPriority(pnPriority); } #endif return S_OK; } void CDocObjectHost::CDOHBindStatusCallback::ResetPrivacyInfo() { _dwPrivacyFlags = 0; if (_pszPolicyRefURL) { LocalFree(_pszPolicyRefURL); _pszPolicyRefURL = NULL; } if (_pszP3PHeader) { LocalFree(_pszP3PHeader); _pszP3PHeader = NULL; } } HRESULT CDocObjectHost::CDOHBindStatusCallback::AddToPrivacyQueue(LPTSTR * ppszUrl, LPTSTR * ppszPolicyRef, LPTSTR * ppszP3PHeader, DWORD dwFlags) { CPrivacyRecord *pRecord = new CPrivacyRecord; if (!pRecord) { return E_OUTOFMEMORY; } HRESULT hRes = S_OK; hRes = pRecord->Init(ppszUrl, ppszPolicyRef, ppszP3PHeader, dwFlags); if (SUCCEEDED(hRes)) _privacyQueue.Queue(pRecord); else delete pRecord; return hRes; } HRESULT CDocObjectHost::CDOHBindStatusCallback::BuildRecord() { HRESULT hRes = S_OK; CDocObjectHost* pdoh = NULL; TCHAR * pszUrl = NULL; if (_pszRedirectedURL) { hRes = AddToPrivacyQueue(&_pszRedirectedURL, &_pszPolicyRefURL, &_pszP3PHeader, _dwPrivacyFlags); goto cleanup; } pdoh = IToClass(CDocObjectHost, _bsc, this); // Get the current URL to add pszUrl = new TCHAR[MAX_URL_STRING]; if (!pszUrl) { hRes = E_OUTOFMEMORY; goto cleanup; } pszUrl[0] = TEXT('\0'); if (pdoh->_pidl) { hRes = IEGetDisplayName(pdoh->_pidl, pszUrl, SHGDN_FORPARSING); } else { LPOLESTR pwUrl = NULL; hRes = pdoh->_GetCurrentPageW(&pwUrl, TRUE); if (SUCCEEDED(hRes)) { StrCpyN(pszUrl, pwUrl, MAX_URL_STRING); OleFree(pwUrl); } } hRes = AddToPrivacyQueue(&pszUrl, &_pszPolicyRefURL, &_pszP3PHeader, _dwPrivacyFlags); cleanup: if (!SUCCEEDED(hRes)) { delete [] pszUrl; } return hRes; } void CDocObjectHost::CDOHBindStatusCallback::_Redirect(LPCWSTR pwzNew) { LPITEMIDLIST pidlNew; WCHAR wszPath[MAX_URL_STRING] = TEXT(""); CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this); LPOLESTR pwszCurrent = NULL; BOOL fAllow = FALSE; if (SUCCEEDED(IECreateFromPath(pwzNew, &pidlNew))) { TraceMsg(TF_SHDNAVIGATE, "CDOH::CBSC::_Redirect calling NotifyRedirect(%s)", pwzNew); if ( pdoh->_pwb ) { pdoh->_pwb->NotifyRedirect(pdoh->_psv, pidlNew, NULL); } // Important - Do this before we destroy the old redirect url BuildRecord(); ResetPrivacyInfo(); // Save te redirected URL if (_pszRedirectedURL) LocalFree( _pszRedirectedURL ); _pszRedirectedURL = StrDup(pwzNew); // We need to account for a bookmark that might appear // in the redirected URL. if(IEILGetFragment(pidlNew, wszPath, SIZECHARS(wszPath))) { LocalFree((LPVOID) pdoh->_pszLocation); pdoh->_pszLocation = StrDup(wszPath); } ILFree(pidlNew); } AddUrlToUrlHistoryStg(pwzNew, NULL, pdoh->_psb, FALSE, NULL, NULL, NULL); // Security: Release the pre-created object and start over for // server-side redirects. The only security check for the // document reference occurs when someone tries to obtain it. // Therefore, we want to orphan the reference if x-domain, so the // client will need to obtain a new reference to the redirected // document. if (SUCCEEDED(pdoh->_GetCurrentPageW(&pwszCurrent, TRUE))) { fAllow = AccessAllowed(pdoh->_psp, pwszCurrent, pwzNew); OleFree(pwszCurrent); } if (!fAllow) pdoh->_ReleasePendingObject(FALSE); } // // In this function, we get the codepage for the current URL. If that's not // CP_ACP, we pass it to Trident via IBindCtx*. // void CDocObjectHost::CDOHBindStatusCallback::_CheckForCodePageAndShortcut(void) { CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this); LPWSTR pwszURL; HRESULT hres = pdoh->_GetCurrentPageW(&pwszURL, TRUE); if (SUCCEEDED(hres)) { UINT codepage = CP_ACP; IOleCommandTarget *pcmdt; VARIANT varShortCutPath = {0}; BOOL fHasShortcut = FALSE; hres = pdoh->QueryService(SID_SHlinkFrame, IID_IOleCommandTarget, (void **)&pcmdt); if(S_OK == hres) { ASSERT(pcmdt); hres = pcmdt->Exec(&CGID_Explorer, SBCMDID_GETSHORTCUTPATH, 0, NULL, &varShortCutPath); // // App Compat: Imagineer Technical returns S_OK for the above Exec // but of course doesn't set the output parameter. // if((S_OK) == hres && VT_BSTR == varShortCutPath.vt && varShortCutPath.bstrVal) { fHasShortcut = TRUE; } pcmdt->Release(); } if(UrlHitsNetW(pwszURL)) { // Don't do this for File: files - we can live // with getting the code page late for file: even // if it slows down file: display somewhat if the // trident parser needs to restarted AddUrlToUrlHistoryStg(pwszURL, NULL, pdoh->_psb, FALSE, NULL, NULL, &codepage); } TraceMsg(DM_DOCCP, "CDOH::CBSC::_CheckForCodePageAndShortcut codepage=%d", codepage); if ((codepage != CP_ACP || fHasShortcut) && _pbc) { // Here is where we pass the codepage to Trident. // (Mars): Clients may have already registered HtmlLoadOptions with // the bind context in order to specify the shortcut path. In this case, // registering it again to set the codepage would fail. However, we should // first verify that this codepage stuff actually gets used. IHtmlLoadOptions *phlo; HRESULT hres = CoCreateInstance(CLSID_HTMLLoadOptions, NULL, CLSCTX_INPROC_SERVER, IID_IHtmlLoadOptions, (void**)&phlo); if (SUCCEEDED(hres) && phlo) { if(codepage != CP_ACP) { hres = phlo->SetOption(HTMLLOADOPTION_CODEPAGE, &codepage, sizeof(codepage)); } if (SUCCEEDED(hres)) { if(fHasShortcut) { // deliberately ignore failures here phlo->SetOption(HTMLLOADOPTION_INETSHORTCUTPATH, varShortCutPath.bstrVal, (lstrlenW(varShortCutPath.bstrVal) + 1)*sizeof(WCHAR)); } _pbc->RegisterObjectParam(L"__HTMLLOADOPTIONS", phlo); } phlo->Release(); } else { TraceMsg(DM_WARNING, "DOH::_CheckForCodePagecut CoCreateInst failed (%x)", hres); } } VariantClear(&varShortCutPath); OleFree(pwszURL); } } #ifdef BETA1_DIALMON_HACK extern void IndicateWinsockActivity(); #endif // BETA1_DIALMON_HACK HRESULT CDocObjectHost::CDOHBindStatusCallback::OnProgress( ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR pwzStatusText) { HRESULT hr = S_OK; HRESULT hrPrivacy = S_OK; TCHAR * pszPrivacyURL = NULL; static TCHAR * pszNULL = NULL; TraceMsg(TF_SHDPROGRESS, "DOH::BSC::OnProgress (%d of %d) ulStatus=%x", ulProgress, ulProgressMax, ulStatusCode); // JEFFWE 4/15/96 Beta 1 Hack - every once in a while, send message // to the hidden window that detects inactivity so that it doesn't // think we are inactive during a long download #ifdef BETA1_DIALMON_HACK IndicateWinsockActivity(); #endif CDocObjectHost * pdoh = IToClass(CDocObjectHost, _bsc, this); #ifdef DEBUG if (pwzStatusText) { char szStatusText[MAX_PATH]; // OK with MAX_PATH UnicodeToAnsi(pwzStatusText, szStatusText, ARRAYSIZE(szStatusText)); TraceMsg(TF_SHDPROGRESS, "DOH::BSC::OnProgress pszStatus=%s", szStatusText); } #endif if (pdoh->_psb) { // we may be switching between multiple proxy/server hosts, so don't prevent // showing them when they change if (_bindst != ulStatusCode || ulStatusCode == BINDSTATUS_FINDINGRESOURCE) { UINT idRes = IDI_STATE_NORMAL; _bindst = ulStatusCode; if (_bindst < ARRAYSIZE(c_aidRes)) idRes = c_aidRes[_bindst]; pdoh->_psb->SendControlMsg(FCW_STATUS, SB_SETICON, STATUS_PANE_NAVIGATION, (LPARAM)g_ahiconState[idRes-IDI_STATE_FIRST], NULL); TCHAR szStatusText[MAX_PATH]; // OK with MAX_PATH if (pwzStatusText) { StrCpyN(szStatusText, pwzStatusText, ARRAYSIZE(szStatusText)); } else { szStatusText[0] = TEXT('\0'); } // // This if-block will open the safe open dialog for OLE Object // and DocObject. // if (_bindst == BINDSTATUS_CLASSIDAVAILABLE) { TraceMsg(TF_SHDPROGRESS, "DOH::BSC::OnProgress got CLSID=%ws", szStatusText); CLSID clsid; // WORK-AROUND: CLSIDFromString does not take LPCOLESTR correctly. HRESULT hresT = CLSIDFromString((LPOLESTR)pwzStatusText, &clsid); if (SUCCEEDED(hresT)) { #ifdef DEBUG if (IsEqualGUID(clsid, CLSID_NULL)) { TraceMsg(DM_WARNING, "DOH::SBC::OnProgress Got CLSID_NULL"); } #endif // // Notice that we don't want to use BROWSERFLAG_MSHTML, // which includes other types of MSHMTL CLSIDs. // In this case, we just want to deal with HTMLDocument. // (We allow XMLViewer docobj and *.MHT and *.MHTML too!) BOOL fIsHTML = (IsEqualGUID(clsid, CLSID_HTMLDocument) || IsEqualGUID(clsid, CLSID_XMLViewerDocObj) || IsEqualGUID(clsid, CLSID_MHTMLDocument)); BOOL fAbortDesktopComponent = FALSE; if(!fIsHTML) { //Check if we are a desktop component. if (_IsDesktopItem(pdoh)) { //Because this is NOT html, then don't show it! fAbortDesktopComponent = TRUE; } } if (fAbortDesktopComponent) { AbortBinding(); hr = E_ABORT; } else { _fBoundToMSHTML = fIsHTML; // Remember this and suppress redundant // AddUrl to history // There is an interval of time between OnProgress and OnObjectAvailable // in which the om might be required. if (fIsHTML && pdoh->_punkPending == NULL) { pdoh->_CreatePendingDocObject(FALSE); } if (pdoh->_punkPending) { IPersist *pip; hresT = pdoh->_punkPending->QueryInterface(IID_IPersist, (LPVOID *) &pip); if (SUCCEEDED(hresT)) { CLSID clsidPending; hresT = pip->GetClassID(&clsidPending); if (SUCCEEDED(hresT) && IsEqualGUID(clsid, clsidPending)) { _pbc->RegisterObjectParam(L"__PrecreatedObject", pdoh->_punkPending); } pip->Release(); } } hresT = pdoh->_MayHaveVirus(clsid); if (hresT == HRESULT_FROM_WIN32(ERROR_CANCELLED)) { hr = E_ABORT; AbortBinding(); if (pdoh->_pmsoctBrowser && pdoh->_fWindowOpen) { pdoh->_pmsoctBrowser->Exec(&CGID_Explorer, SBCMDID_CANCELANDCLOSE, 0, NULL, NULL); } } } } else { TraceMsg(DM_ERROR, "DOH::BSC::OnProgress CLSIDFromString failed %x", hresT); } // // Notice that URLMON will call IPersistMoniker::Load right // after we return from this notification. Therefore, this // is the latest moment we have a chance to pass the code // page to Trident. // _CheckForCodePageAndShortcut(); } else if (_bindst == BINDSTATUS_CACHEFILENAMEAVAILABLE) { TraceMsg(DM_SELFASC, "DOH::OnProgress got BINDSTATUS_CACHEFILENAMEAVAILABLE"); _fSelfAssociated = IsAssociatedWithIE(pwzStatusText); if(_pszCacheFileName) LocalFree(_pszCacheFileName); _pszCacheFileName = StrDup(pwzStatusText); } else if (_bindst == BINDSTATUS_CONTENTDISPOSITIONATTACH) { TCHAR szURL[MAX_URL_STRING]; TCHAR * pszURL = szURL; HRESULT hresT; hresT = pdoh->_GetCurrentPage(szURL, ARRAYSIZE(szURL), TRUE); if (SUCCEEDED(hresT)) { UINT uRet; if (_pszRedirectedURL && lstrlen(_pszRedirectedURL)) { pszURL = _pszRedirectedURL; } IUnknown * punk; hresT = pdoh->QueryInterface(IID_IUnknown, (void**)&punk); if (SUCCEEDED(hresT)) { uRet = OpenSafeOpenDialog(pdoh->_hwnd, DLG_SAFEOPEN, NULL, pszURL, NULL, szStatusText, NULL, pdoh->_uiCP, punk); switch(uRet) { case IDOK: // // Set this flag to avoid poppping this dialog box twice. // pdoh->_fConfirmed = TRUE; break; // continue download case IDD_SAVEAS: CDownLoad_OpenUI(pdoh->_pmkCur, _pbc, FALSE, TRUE, NULL, NULL, NULL, NULL, NULL, _pszRedirectedURL, pdoh->_uiCP, punk); ATOMICRELEASE(_pbc); ATOMICRELEASE(_psvPrev); // fall thru to AbortBinding case IDCANCEL: pdoh->_CancelPendingNavigation(FALSE); AbortBinding(); if (uRet == IDCANCEL) { _fAborted = TRUE; } break; } punk->Release(); } } } if ( ( _bindst >= BINDSTATUS_FINDINGRESOURCE && _bindst <= BINDSTATUS_SENDINGREQUEST) || _bindst == BINDSTATUS_PROXYDETECTING) { TCHAR szTemplate[MAX_PATH]; // OK with MAX_PATH UINT idResource = IDS_BINDSTATUS+_bindst; if ( _bindst == BINDSTATUS_PROXYDETECTING ) { idResource = IDS_BINDSTATUS_PROXYDETECTING; } // If we are connecting over proxy, don't say "web site found". // if (fOnProxy() && idResource == IDS_BINDSTATUS_SEND) { idResource = IDS_BINDSTATUS_CON; TCHAR szUrl[MAX_URL_STRING]; pdoh->_GetCurrentPage(szUrl, SIZECHARS(szUrl)); DWORD cchStatusText = SIZECHARS(szStatusText); UrlGetPart(szUrl, szStatusText, &cchStatusText, URL_PART_HOSTNAME, 0); } if (MLLoadString(idResource, szTemplate, ARRAYSIZE(szTemplate))) { BSCMSGS("OnProgress szTemplate=", szTemplate); TCHAR szMessage[MAX_PATH]; // OK with MAX_PATH BOOL fSuccess = wnsprintf(szMessage, ARRAYSIZE(szMessage), szTemplate, szStatusText); if (fSuccess) { BSCMSGS("OnProgress szMessage=", szMessage); pdoh->_SetStatusText(szMessage); } } } } DWORD dwState = 0; switch (ulStatusCode) { case BINDSTATUS_REDIRECTING: // they're redirecting. treat this as a rename. _Redirect(pwzStatusText); break; case BINDSTATUS_FINDINGRESOURCE: dwState = PROGRESS_FINDING; ASSERT(!ulProgressMax); break; case BINDSTATUS_SENDINGREQUEST: dwState = PROGRESS_SENDING; ASSERT(!ulProgressMax); break; //Handle privacy notifications case BINDSTATUS_COOKIE_SENT: BSCMSG(TEXT("OnProgress - Received BINDSTATUS_COOKIE_SENT"), 0 ,0); if (pwzStatusText && *pwzStatusText) { pszPrivacyURL = new TCHAR[MAX_URL_STRING]; if (!pszPrivacyURL) break; StrCpyN(pszPrivacyURL, pwzStatusText, MAX_URL_STRING); hrPrivacy = AddToPrivacyQueue(&pszPrivacyURL, &pszNULL, &pszNULL, COOKIEACTION_READ); if (!SUCCEEDED(hrPrivacy)) delete [] pszPrivacyURL; } else { _dwPrivacyFlags |= COOKIEACTION_READ; } break; case BINDSTATUS_COOKIE_SUPPRESSED: BSCMSG(TEXT("OnProgress - Received BINDSTATUS_COOKIE_SUPPRESSED"), 0, 0); if (pwzStatusText && *pwzStatusText) { pszPrivacyURL = new TCHAR[MAX_URL_STRING]; if (!pszPrivacyURL) break; StrCpyN(pszPrivacyURL, pwzStatusText, MAX_URL_STRING); hrPrivacy = AddToPrivacyQueue(&pszPrivacyURL, &pszNULL, &pszNULL, COOKIEACTION_SUPPRESS); if (!SUCCEEDED(hrPrivacy)) delete [] pszPrivacyURL; } else { _dwPrivacyFlags |= COOKIEACTION_SUPPRESS; } break; case BINDSTATUS_COOKIE_STATE_UNKNOWN: BSCMSG(TEXT("Shdocvw should never BINDSTATUS_COOKIE_STATE_UNKNOWN from Wininet/Urlmon"), 0, 0); break; case BINDSTATUS_COOKIE_STATE_ACCEPT: BSCMSG(TEXT("OnProgress - Received BINDSTATUS_COOKIE_STATE_ACCEPT"), 0, 0); if (pwzStatusText && *pwzStatusText) { pszPrivacyURL = new TCHAR[MAX_URL_STRING]; if (!pszPrivacyURL) break; StrCpyN(pszPrivacyURL, pwzStatusText, MAX_URL_STRING); hrPrivacy = AddToPrivacyQueue(&pszPrivacyURL, &pszNULL, &pszNULL, COOKIEACTION_ACCEPT); if (!SUCCEEDED(hrPrivacy)) delete [] pszPrivacyURL; } else { _dwPrivacyFlags |= COOKIEACTION_ACCEPT; } break; case BINDSTATUS_COOKIE_STATE_REJECT: BSCMSG(TEXT("OnProgress - Received BINDSTATUS_COOKIE_STATE_REJECT"), 0, 0); if (pwzStatusText && *pwzStatusText) { pszPrivacyURL = new TCHAR[MAX_URL_STRING]; if (!pszPrivacyURL) break; StrCpyN(pszPrivacyURL, pwzStatusText, MAX_URL_STRING); hrPrivacy = AddToPrivacyQueue(&pszPrivacyURL, &pszNULL, &pszNULL, COOKIEACTION_REJECT); if (!SUCCEEDED(hrPrivacy)) delete [] pszPrivacyURL; } else { _dwPrivacyFlags |= COOKIEACTION_REJECT; } break; case BINDSTATUS_COOKIE_STATE_PROMPT: BSCMSG(TEXT("Shdocvw should never BINDSTATUS_COOKIE_STATE_PROMPT from Wininet/Urlmon"), 0, 0); break; case BINDSTATUS_COOKIE_STATE_LEASH: BSCMSG(TEXT("OnProgress - Received BINDSTATUS_COOKIE_STATE_LEASH"), 0, 0); if (pwzStatusText && *pwzStatusText) { pszPrivacyURL = new TCHAR[MAX_URL_STRING]; if (!pszPrivacyURL) break; StrCpyN(pszPrivacyURL, pwzStatusText, MAX_URL_STRING); hrPrivacy = AddToPrivacyQueue(&pszPrivacyURL, &pszNULL, &pszNULL, COOKIEACTION_LEASH); if (!SUCCEEDED(hrPrivacy)) delete [] pszPrivacyURL; } else { _dwPrivacyFlags |= COOKIEACTION_LEASH; } break; case BINDSTATUS_COOKIE_STATE_DOWNGRADE: BSCMSG(TEXT("OnProgress - Received BINDSTATUS_COOKIE_STATE_DOWNGRADE"), 0, 0); if (pwzStatusText && *pwzStatusText) { pszPrivacyURL = new TCHAR[MAX_URL_STRING]; if (!pszPrivacyURL) break; StrCpyN(pszPrivacyURL, pwzStatusText, MAX_URL_STRING); hrPrivacy = AddToPrivacyQueue(&pszPrivacyURL, &pszNULL, &pszNULL, COOKIEACTION_DOWNGRADE); if (!SUCCEEDED(hrPrivacy)) delete [] pszPrivacyURL; } else { _dwPrivacyFlags |= COOKIEACTION_DOWNGRADE; } break; case BINDSTATUS_COMPACT_POLICY_RECEIVED: _dwPrivacyFlags |= PRIVACY_URLHASCOMPACTPOLICY; break; case BINDSTATUS_POLICY_HREF: BSCMSG(TEXT("OnProgress - Received BINDSTATUS_POLICY_HREF"), 0, 0); ASSERT(pwzStatusText && *pwzStatusText); // We are getting two notifications from urlmon, once that is fixed, need to uncomment this assert //ASSERT(!_pszPolicyRefURL); if (_pszPolicyRefURL) { LocalFree(_pszPolicyRefURL); } _pszPolicyRefURL = StrDup(pwzStatusText); _dwPrivacyFlags |= PRIVACY_URLHASPOLICYREFHEADER; break; case BINDSTATUS_P3P_HEADER: BSCMSG(TEXT("OnProgress - Received BINDSTATUS_P3P_HEADER"), 0, 0); ASSERT(pwzStatusText && *pwzStatusText); // We are getting two notifications from urlmon, once that is fixed, need to uncomment this assert //ASSERT(!_pszP3PHeader); if (_pszP3PHeader) { LocalFree(_pszP3PHeader); } _pszP3PHeader = StrDup(pwzStatusText); _dwPrivacyFlags |= PRIVACY_URLHASP3PHEADER; break; } if (dwState) { pdoh->_OnSetProgressPos(ulProgress, dwState); } if (BINDSTATUS_BEGINDOWNLOADDATA == ulStatusCode) { _cbContentLength = ulProgress; } else if (BINDSTATUS_MIMETYPEAVAILABLE == ulStatusCode) { // delegate to media bar if this is a media mime-type if ( pwzStatusText && ( !StrCmpNIW(pwzStatusText, _T("audio"), 5) || !StrCmpNIW(pwzStatusText, _T("video"), 5))) { if (pdoh->_DelegateToMediaBar(NULL, pwzStatusText)) { // Cancel the navigation pdoh->_CancelPendingNavigation(FALSE); AbortBinding(); _fAborted = TRUE; if (pdoh->_pwb) { pdoh->_pwb->SetNavigateState(BNS_NORMAL); } } } } } #ifndef NO_DELEGATION if (_pbscChained) { _pbscChained->OnProgress(ulProgress, ulProgressMax, ulStatusCode, pwzStatusText); } #endif return hr; } HRESULT CDocObjectHost::CDOHBindStatusCallback::OnDataAvailable( /* [in] */ DWORD grfBSC, /* [in] */ DWORD dwSize, /* [in] */ FORMATETC *pformatetc, /* [in] */ STGMEDIUM *pstgmed) { BSCMSG(TEXT("OnDataAvailable (grf,pstg)"), grfBSC, pstgmed); #ifndef NO_DELEGATION if (_pbscChained) { _pbscChained->OnDataAvailable(grfBSC, dwSize, pformatetc, pstgmed); } #endif return S_OK; } void CDocObjectHost::CDOHBindStatusCallback::_UpdateSSLIcon(void) { CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this); ASSERT(_pib); // // if we have already been set by our object, we dont // want to override it. if (_pib && !pdoh->_fSetSecureLock) { pdoh->_eSecureLock = SECURELOCK_SET_UNSECURE; IWinInetInfo* pwinet; HRESULT hresT = _pib->QueryInterface(IID_IWinInetInfo, (LPVOID*)&pwinet); if (SUCCEEDED(hresT)) { DWORD dwOptions = 0; DWORD cbSize = SIZEOF(dwOptions); hresT = pwinet->QueryOption(INTERNET_OPTION_SECURITY_FLAGS, (LPVOID)&dwOptions, &cbSize); TraceMsg(DM_SSL, "pwinet->QueryOptions hres=%x dwOptions=%x", hresT, dwOptions); if (SUCCEEDED(hresT)) { LPWSTR pwzUrl; pdoh->_fSetSecureLock = TRUE; if(dwOptions & SECURITY_FLAG_SECURE) { pdoh->_dwSecurityStatus = dwOptions; if (pdoh->_dwSecurityStatus & SECURITY_FLAG_40BIT) { pdoh->_eSecureLock = SECURELOCK_SET_SECURE40BIT; } else if (pdoh->_dwSecurityStatus & SECURITY_FLAG_128BIT) { pdoh->_eSecureLock = SECURELOCK_SET_SECURE128BIT; } else if (pdoh->_dwSecurityStatus & SECURITY_FLAG_FORTEZZA) { pdoh->_eSecureLock = SECURELOCK_SET_FORTEZZA; } else if (pdoh->_dwSecurityStatus & SECURITY_FLAG_56BIT) { pdoh->_eSecureLock = SECURELOCK_SET_SECURE56BIT; } } else if (SUCCEEDED(_GetRequestFlagFromPIB(_pib, &dwOptions)) && (dwOptions & INTERNET_REQFLAG_FROM_CACHE) && SUCCEEDED(pdoh->_GetCurrentPageW(&pwzUrl, TRUE))) { // // when secure pages are cached, they lose their // security context, but should still be displayed // as secure. therefore we use the UnknownBit level // of security. // if(URL_SCHEME_HTTPS == GetUrlSchemeW(pwzUrl)) pdoh->_eSecureLock = SECURELOCK_SET_SECUREUNKNOWNBIT; OleFree(pwzUrl); } } else { pdoh->_dwSecurityStatus = 0; } // we will update the browser when we are activated pwinet->Release(); } else { TraceMsg(DM_SSL, "QI to IWinInetInfo failed"); } TraceMsg(DM_SSL, "[%X] UpdateSslIcon() setting _eSecureLock = %d", pdoh, pdoh->_eSecureLock); } else { TraceMsg(DM_SSL, "[%X] UpdateSslIcon() already set _eSecureLock = %d", pdoh, pdoh->_eSecureLock); } } HRESULT CDocObjectHost::CDOHBindStatusCallback::OnObjectAvailable( /* [in] */ REFIID riid, /* [iid_is][in] */ IUnknown *punk) { BSCMSG(TEXT("OnObjectAvailable (riid,punk)"), riid, punk); CDocObjectHost * pdoh = IToClass(CDocObjectHost, _bsc, this); #ifdef DEBUG extern DWORD g_dwPerf; PERFMSG(TEXT("OnObjectAvailable called"), GetCurrentTime()-g_dwPerf); g_dwPerf = GetCurrentTime(); #endif // If we get this far, DocObject has been inited by UrlMon or // in process of retrieving pending object via IOleCommandTarget::Exec() if (pdoh->_punkPending) { pdoh->_fPendingNeedsInit = 0; } // // When this notification is called first time, we should ask // the browser to activate us (which causes BindToObject). // if (pdoh->_pole==NULL && punk) { HRESULT hresT = punk->QueryInterface(IID_IOleObject, (LPVOID*)&(pdoh->_pole)); if (SUCCEEDED(hresT)) { IOleDocument * pmsod = NULL; pdoh->_OnBound(S_OK); hresT = (pdoh->_fDontInPlaceNavigate() ? E_NOINTERFACE : punk->QueryInterface(IID_IOleDocument, (LPVOID*)&pmsod)); if (SUCCEEDED(hresT)) { pmsod->Release(); // We don't use it at this point. // Case 1: DocObject OPENMSG(TEXT("OnObjectAvailable ASYNC DocObject")); ASSERT(pdoh->_psb); if (pdoh->_pmsoctBrowser) { VARIANT var = {0}; VARIANT varOut = {0}; // Tell the host that we know this is a document object. V_VT(&var) = VT_BOOL; V_BOOL(&var) = VARIANT_TRUE; pdoh->_pmsoctBrowser->Exec(&CGID_ShellDocView, SHDVID_FIREFILEDOWNLOAD, 0, &var, &varOut); } #ifdef FEATURE_PICS BOOL fSupportsPICS = FALSE; if (pdoh->_PicsProcBase._fbPicsWaitFlags) { VARIANTARG v; v.vt = VT_UNKNOWN; v.byref = (LPVOID)(IOleCommandTarget *)&pdoh->_PicsProcBase; hresT = IUnknown_Exec(pdoh->_pole, &CGID_ShellDocView, SHDVID_CANSUPPORTPICS, 0, &v, NULL); if (hresT == S_OK) { BSCMSG(TEXT("OnObjectAvailable - obj supports PICS"), 0, 0); fSupportsPICS = TRUE; } else { BSCMSG(TEXT("OnObjectAvailable - obj either doesn't support IOleCommandTarget or doesn't support PICS"), hresT, 0); } } #endif BSCMSG(TEXT("OnObjectAvailable calling pdoh->_Navigate"), 0, 0); pdoh->_SetUpTransitionCapability(); _UpdateSSLIcon(); #ifdef FEATURE_PICS // If we can't get labels out of the document (or don't need // to, because we already got one from a bureau or HTTP header), // see if we can complete PICS checking now. // if (!fSupportsPICS) { pdoh->_PicsProcBase._fbPicsWaitFlags &= ~(PICS_WAIT_FOR_INDOC | PICS_WAIT_FOR_END); /* no indoc ratings */ if (!pdoh->_PicsProcBase._fbPicsWaitFlags) { TraceMsg(DM_PICS, "OnObjectAvailable calling _HandlePicsChecksComplete"); pdoh->_PicsProcBase._HandlePicsChecksComplete(); } } #endif } else { // Case 2: OLE object OPENMSG(TEXT("OnDataAvailable ASYNC OLE Object")); pdoh->_ActivateOleObject(); // We need to tell the browser not to add this one to the // browse history. // We also want to close the browser window if this is the first // download - that's why we pass TRUE - to treat it like a code // download // if (pdoh->_dwAppHack & BROWSERFLAG_DONTAUTOCLOSE) { pdoh->_CancelPendingNavigation(FALSE); } else { pdoh->_CancelPendingNavigation(TRUE, FALSE, FALSE, TRUE); } if (pdoh->_fDelegatedNavigation) { VARIANT varOut = {0}; IDocNavigate * pDocNavigate; pdoh->_pmsoctBrowser->Exec(&CGID_ShellDocView, SHDVID_FIREFILEDOWNLOAD, 0, NULL, &varOut); HRESULT hr = E_FAIL; if ( pdoh->_pwb ) { hr = pdoh->_pwb->QueryInterface(IID_PPV_ARG(IDocNavigate, &pDocNavigate)); } if (S_OK == hr) { pDocNavigate->OnReadyStateChange(NULL, READYSTATE_COMPLETE); pDocNavigate->Release(); } } // // If this is the very first page, we should draw the background. // pdoh->_fDrawBackground = TRUE; //If the following assert is hit, then that means that we are // going to invalidate the desktop window (which is not // intended here) // ASSERT(pdoh->_hwnd); InvalidateRect(pdoh->_hwnd, NULL, TRUE); } } else { _fBoundToNoOleObject = TRUE; } } // Add privacy info to Trident's list if possible if (_fBoundToMSHTML) { HRESULT hRes = E_FAIL; IServiceProvider * pSP = NULL; IPrivacyServices * pPrivacyServices = NULL; DWORD dwTopLevelFlag = 0; // QueryService the Trident for the IPrivacyServices interface hRes = pdoh->_pole->QueryInterface(IID_IServiceProvider, (void**)&pSP); if (SUCCEEDED(hRes) && pSP) { hRes = pSP->QueryService(IID_IPrivacyServices,IID_IPrivacyServices,(void**)&pPrivacyServices); pSP->Release(); } if (pPrivacyServices) { if (pdoh->_psp && pdoh->_psb && IsTopFrameBrowser(pdoh->_psp, pdoh->_psb)) { dwTopLevelFlag |= PRIVACY_URLISTOPLEVEL; } // Add dummy marker since Trident would have added its records during the BindToStorage call // initiated due to shdocvw's current bind only if we are top level if (dwTopLevelFlag) pPrivacyServices->AddPrivacyInfoToList( TEXT(""), NULL, NULL, 0, PRIVACY_URLISTOPLEVEL); // Add each item in the privacy queue (accumulated from redirections) to Trident's list CPrivacyRecord *pPrivacyRecord = _privacyQueue.Dequeue(); if (pPrivacyRecord) { while (pPrivacyRecord) { pPrivacyRecord->_dwPrivacyFlags |= dwTopLevelFlag; pPrivacyServices->AddPrivacyInfoToList( pPrivacyRecord->_pszUrl, pPrivacyRecord->_pszPolicyRefUrl, pPrivacyRecord->_pszP3PHeader, 0, pPrivacyRecord->_dwPrivacyFlags); delete pPrivacyRecord; // Add the dummy marker separating top level records if this is top level if (dwTopLevelFlag) pPrivacyServices->AddPrivacyInfoToList( TEXT(""), NULL, NULL, 0, PRIVACY_URLISTOPLEVEL); pPrivacyRecord = _privacyQueue.Dequeue(); } // Add the last one redirected url from the class itself since this was not added to the list _dwPrivacyFlags |= dwTopLevelFlag; pPrivacyServices->AddPrivacyInfoToList(_pszRedirectedURL, _pszPolicyRefURL, _pszP3PHeader, 0, _dwPrivacyFlags); } else { TCHAR szUrl[MAX_URL_STRING]; szUrl[0] = TEXT('\0'); // Get the url used for binding if (pdoh->_pidl) { hRes = IEGetDisplayName(pdoh->_pidl, szUrl, SHGDN_FORPARSING); } else { LPOLESTR pwUrl = NULL; hRes = pdoh->_GetCurrentPageW(&pwUrl, TRUE); if (SUCCEEDED(hRes)) { StrCpyN(szUrl, pwUrl, ARRAYSIZE(szUrl)); OleFree(pwUrl); } } if (SUCCEEDED(hRes)) { _dwPrivacyFlags |= dwTopLevelFlag; pPrivacyServices->AddPrivacyInfoToList(szUrl, _pszPolicyRefURL, _pszP3PHeader, 0, _dwPrivacyFlags); } } pPrivacyServices->Release(); } } #ifndef NO_DELEGATION if (_pbscChained) { _pbscChained->OnObjectAvailable(riid, punk); } #endif return S_OK; } HRESULT CDocObjectHost::CDOHBindStatusCallback::OnLowResource(DWORD reserved) { BSCMSG(TEXT("OnLowResource"), 0, 0); #ifndef NO_DELEGATION if (_pbscChained) { _pbscChained->OnLowResource(reserved); } #endif return S_OK; } HRESULT CDocObjectHost::CDOHBindStatusCallback::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR __RPC_FAR * ppwzAdditionalHeaders) { HRESULT hres; #ifndef NO_DELEGATION if (_pnegotiateChained) { hres = _pnegotiateChained->BeginningTransaction(szURL, szHeaders, dwReserved, ppwzAdditionalHeaders); } else { #endif // Here we pass headers to URLMon hres=BuildAdditionalHeaders((LPCTSTR) _pszHeaders,(LPCWSTR *) ppwzAdditionalHeaders); #ifndef NO_DELEGATION } #endif return hres; } const WCHAR g_wszPicsLabel[] = L"\r\nPICS-Label:"; HRESULT CDocObjectHost::CDOHBindStatusCallback::OnResponse(DWORD dwResponseCode, LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders) { #ifndef NO_DELEGATION if (_pnegotiateChained) { _pnegotiateChained->OnResponse(dwResponseCode, szResponseHeaders, szRequestHeaders, pszAdditionalRequestHeaders); } else { #endif #ifndef NO_DELEGATION } #endif #ifdef FEATURE_PICS /* CODEWORK: For next release, all response headers should be handled * generically through _OnHttpEquiv, and rating labels should be * processed there instead of through a private IOleCommandTarget * interface with Trident. */ /* NOTE: We still need to check for the PICS label header here, even * if we chained to Trident or whoever above. */ // (jbeda) this _dwPicsLabelSource stuff looks really screwy... CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this); if (pdoh->_PicsProcBase._fbPicsWaitFlags & PICS_WAIT_FOR_INDOC) { LPCWSTR pwszPicsLabel = StrStrW(szResponseHeaders, g_wszPicsLabel); if (pwszPicsLabel != NULL) { pdoh->_PicsProcBase._dwPicsLabelSource=PICS_LABEL_FROM_HEADER; pwszPicsLabel += ARRAYSIZE(g_wszPicsLabel); /* skip \r\n and label name */ LPCWSTR pwszPicsLabelEnd = StrChrW(pwszPicsLabel, L'\r'); if (pwszPicsLabelEnd == NULL) { // NOTE: lstrlenW doesn't work on Win95, so we do this manually. for (pwszPicsLabelEnd = pwszPicsLabel; *pwszPicsLabelEnd; pwszPicsLabelEnd++) ; } if (pwszPicsLabel && (pwszPicsLabelEnd > pwszPicsLabel)) { WCHAR* pszLabel = new WCHAR[((int)(pwszPicsLabelEnd - pwszPicsLabel)) + 1]; if (pszLabel) { // // pwszPicsLabel may not be NULL terminated so use memcpy to // move it. Memory allocated by new is zero filled so // pszLabel doesn't have to have L'\0' appeneded. // memcpy(pszLabel, pwszPicsLabel, ((int)(pwszPicsLabelEnd - pwszPicsLabel)) * sizeof(WCHAR)); pdoh->_PicsProcBase._HandleInDocumentLabel(pszLabel); delete pszLabel; } } } else { pdoh->_PicsProcBase._dwPicsLabelSource=PICS_LABEL_FROM_PAGE; } } #endif return S_OK; } HRESULT CDocObjectHost::CDOHBindStatusCallback::GetWindow(REFGUID rguidReason, HWND* phwnd) { CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this); if (!phwnd) return E_POINTER; if (pdoh->_psb) { pdoh->_psb->GetWindow(phwnd); } else { *phwnd = pdoh->_hwnd; } return S_OK; } HRESULT CDocObjectHost::CDOHBindStatusCallback::OnSecurityProblem(DWORD dwProblem) { // force UI - return S_FALSE for all problems return S_FALSE; } #define BUG_EXEC_ON_FAILURE //nash:31526 HRESULT CDocObjectHost::CDOHBindStatusCallback::OnStopBinding(HRESULT hrError, LPCWSTR szError) { BSCMSG(TEXT("OnStopBinding"), this, hrError); _fBinding = FALSE; CDocObjectHost * pdoh = IToClass(CDocObjectHost, _bsc, this); LPWSTR pwzHeaders = NULL; BOOL fShouldDisplayError = TRUE; DWORD dwStatusCode = 0; // We use 0 to mean no status yet DWORD dwStatusCodeSize = sizeof(dwStatusCode); BOOL bSuppressUI = FALSE; BOOL fAsyncDownload = FALSE; BOOL fAborted = _fAborted; BOOL fCancelAutoSearch = FALSE; BOOL fNavigateErrorFired = FALSE; // I cannot tell if _HandleHttpErrors are really mutually exclusive from the AutoSearching. // Therefore I am adding a flag to make sure we don't fire NavigateError twice. _fAborted = FALSE; _privacyQueue.Reset(); ResetPrivacyInfo(); // // this is to protect against urlmons behavior of returning // an async error and sync error on the same call. if (pdoh->_fSyncBindToObject && FAILED(hrError)) { pdoh->_hrOnStopBinding = hrError; return S_OK; } // if aborting to let Document.Write work...pretend everything is cool if (_fDocWriteAbort && hrError == E_ABORT) hrError = S_OK; // Why not use the cached value? // pdoh->_GetOfflineSilent(0, &bSuppressUI); bSuppressUI = (_bFrameIsSilent || _IsDesktopItem(pdoh)) ? TRUE : FALSE; _bindst = 0; // go back to the normal state if (_pbc && pdoh->_punkPending) { _pbc->RevokeObjectParam(L"__PrecreatedObject"); } if (!_pbc) { ASSERT(0); return S_OK; } // NOTES: Guard against last Release by _RevokeObjectParam AddRef(); if (pdoh->_pwb) { pdoh->_pwb->SetNavigateState(BNS_NORMAL); } if (pdoh->_psb) { // paranoia pdoh->_psb->SetStatusTextSB(NULL); } BSCMSG("OnStopBinding calling _RevokeObjectParam", this, _pbc); _RevokeObjectParam(_pbc); _pbc->RevokeObjectParam(WSZGUID_OPID_DocObjClientSite); // // If the error code is a mapped error code (by URLMON), get the // real error code from IBinding for display purpose. // HRESULT hrDisplay = hrError; // assume they are the same #define ENABLE_WHEN_GETBINDRESULT_STARTS_WORKING #ifdef ENABLE_WHEN_GETBINDRESULT_STARTS_WORKING if (hrError>=INET_E_ERROR_FIRST && hrError<=INET_E_ERROR_LAST) { // // We come here when _pib==NULL, if URLMON synchronously fails // (such as a bad protocol). // // ASSERT(_pib); // if (_pib) { CLSID clsid; LPWSTR pwszError = NULL; HRESULT hresT=_pib->GetBindResult(&clsid, (DWORD *)&hrDisplay, &pwszError, NULL); TraceMsg(TF_SHDBINDING, "DOH::OnStopBinding called GetBindResult %x->%x (%x)", hrError, hrDisplay, hresT); if (SUCCEEDED(hresT)) { // // URLMON returns a native Win32 error. // if (hrDisplay && SUCCEEDED(hrDisplay)) { hrDisplay = HRESULT_FROM_WIN32(hrDisplay); } // // URLMON is not supposed to return 0 as the error code, // which causes a "successfully done" error msgbox. // AssertMsg(hrDisplay != S_OK, TEXT("Call JohannP if you see this assert.")); if (pwszError) { OleFree(pwszError); } } } } #endif TraceMsg(TF_SHDBINDING, "DOH::BSC::OnStopBinding binding failed %x (hrDisplay=%x)", hrError, hrDisplay); // // HACK: If the object is associated with IE/Shell itself, but has // no CLSID, we'll force MSHTML. // // if (_fSelfAssociated && (hrError==MK_E_INVALIDEXTENSION || hrError==REGDB_E_CLASSNOTREG)) { // hrError = _HandleSelfAssociate(); // } if (_pib) { // we dont need to do the expiry stuff here anymore. // now mshtml should be doing it through the IPersistHistory // get the expire info // The HTTP rules for expiration are // Expires: 0 expire immediately // if Expires: <= Date: expire immediately // if Expires: bad format expire immediately IWinInetHttpInfo * phi; if (SUCCEEDED(_pib->QueryInterface(IID_IWinInetHttpInfo, (LPVOID*)&phi))) { BYTE abBuffer[256]; // We don't care about this data, just DWORD cbBuffer=sizeof(abBuffer); // whether it exists or not if (phi->QueryInfo(HTTP_QUERY_LAST_MODIFIED, &abBuffer, &cbBuffer, NULL, 0) == S_OK) pdoh->_fhasLastModified = TRUE; if (phi->QueryInfo(HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwStatusCode, &dwStatusCodeSize, NULL, 0) != S_OK) { dwStatusCode = 0; // failed to get status code dwStatusCodeSize = 0; // failed to get status code } // This code will decide if we should display a popup error; // essentially, it detects if we can reasonably assume that // HTML was returned in the error case; if so, we believe that // it is an error page, so we let that display rather than a // popup. if (dwStatusCode) { // We got a status code; let's see if we have a // content-type. // HTTP retcode 204 is a "succeeded, do nothing" retcode // So we should always suppress the popup; further, it is // spec'd to NEVER have content, so we do this before checking // for content-type. // So is 100 // 100 is not in wininet.h if (dwStatusCode == HTTP_STATUS_NO_CONTENT) fShouldDisplayError = FALSE; // what is max header size? CHAR szContentType[1024]; DWORD dwContentTypeSize = sizeof(szContentType); // This code handles a bug in URLMON where it tells us // INET_E_DATA_NOT_AVAILABLE when in fact the // data _was_ available. We don't want any future // errors affected by this, so we restrict this // hack to less than 600, and ONLY for the // INET_E_DATA_NOT_AVAILABLE case. if (hrError == INET_E_DATA_NOT_AVAILABLE && dwStatusCode < 600 && phi->QueryInfo(HTTP_QUERY_CONTENT_TYPE, &szContentType, &dwContentTypeSize, NULL, 0) == S_OK) { fShouldDisplayError = FALSE; } // // Handle http errors. // // Let's wrap the firing in case it is not the first attempt in future if (dwStatusCode >= 400 && dwStatusCode <= 599) { if (!fNavigateErrorFired) { pdoh->_FireNavigateErrorHelper(NULL, dwStatusCode, &fCancelAutoSearch); fNavigateErrorFired = TRUE; } if (!fCancelAutoSearch) { _HandleHttpErrors(dwStatusCode, _cbContentLength, pdoh); } else if (!pdoh->_fCanceledByBrowser) { pdoh->_CancelPendingNavigation(FALSE, FALSE); } } } phi->Release(); } ATOMICRELEASE(_pib); } ATOMICRELEASE(_psvPrev); // // If the object does not support IOleObject, treat it as if we failed // to bind. // if (_fBoundToNoOleObject) { ASSERT(SUCCEEDED(hrError)); hrError = MK_E_INVALIDEXTENSION; } // need to handle navigation in successful proxy response but w/ // 404 error. tonyci 13nov96. for autosearching & autosuffixing if (FAILED(hrError)) { BOOL fAddToMRU = FALSE; pdoh->_fDrawBackground = TRUE; TCHAR szURL[MAX_URL_STRING+1]; szURL[0] = TEXT('\0'); // // It seems that in some of the case of hrError the code counts on dwStatusCode being set // dwStatus is set exactly when the real error code was obtained from IBinding for display purpose // For the other case I am going to use hrError // if (!fNavigateErrorFired) { if (dwStatusCode) { pdoh->_FireNavigateErrorHelper(NULL, dwStatusCode, &fCancelAutoSearch); fNavigateErrorFired = TRUE; } else if (hrError>=INET_E_ERROR_FIRST && hrError<=INET_E_ERROR_LAST) { pdoh->_FireNavigateErrorHelper(NULL, hrError, &fCancelAutoSearch); fNavigateErrorFired = TRUE; } } if (pdoh->_pmkCur) { pdoh->_GetCurrentPage(szURL,ARRAYSIZE(szURL)); } TraceMsg(TF_SHDBINDING, "DOH::OnStopBinding hrError=%x", hrError); pdoh->_OnSetProgressPos(0, PROGRESS_RESET); switch(hrError) { // // If pmk->BindToObject is failed because of "binding", we should // offer an option to download it as a file. // #ifdef BUG_EXEC_ON_FAILURE case INET_E_CANNOT_INSTANTIATE_OBJECT: TraceMsg(TF_SHDBINDING, "DOH::OnStopBinding IDS_ERR_OLESVR"); _SetSearchInfo(pdoh, 0, FALSE, FALSE, FALSE); // reset info goto Lexec; case INET_E_CANNOT_LOAD_DATA: TraceMsg(TF_SHDBINDING, "DOH::OnStopBinding IDS_ERR_LOAD"); _SetSearchInfo(pdoh, 0, FALSE, FALSE, FALSE); // reset info goto Lexec; #else case INET_E_CANNOT_INSTANTIATE_OBJECT: _SetSearchInfo(pdoh, 0, FALSE, FALSE, FALSE); // reset info if (MLShellMessageBox(pdoh->_hwnd, MAKEINTRESOURCE(IDS_ERR_OLESVR), MAKEINTRESOURCE(IDS_TITLE), MB_YESNO|MB_ICONERROR, szURL) == IDYES) { IUnknown * punk; HRESULT hresT = pdoh->QueryInterface(IID_IUnknown, (void**)&punk); if(SUCCEEDED(hresT)) { if (!fAborted) { CDownLoad_OpenUI(pdoh->_pmkCur, _pbc, FALSE, TRUE, NULL, NULL, NULL, NULL, NULL, _pszRedirectedURL, pdoh->_uiCP, punk); } punk->Release(); } } break; case INET_E_CANNOT_LOAD_DATA: _SetSearchInfo(pdoh, 0, FALSE, FALSE, FALSE); // reset info // e.g. click on .xls link when doc already open/modified/locked // and say 'cancel' // if (MLShellMessageBox(pdoh->_hwnd, MAKEINTRESOURCE(IDS_ERR_LOAD), MAKEINTRESOURCE(IDS_TITLE), MB_YESNO|MB_ICONERROR, szURL) == IDYES) { IUnknown *punk; HRESULT hresT = pdoh->QueryInterface(IID_IUnknown, (void**)&punk); if(SUCCEEDED(hresT)) { if (!fAborted) { CDownLoad_OpenUI(pdoh->_pmkCur, _pbc, FALSE, TRUE, NULL, NULL, NULL, NULL, _pszRedirectedURL, pdoh->_uiCP, punk); } punk->Release(); } } break; #endif // // NOTES: According to JohannP, URLMON will give us // REGDB_E_CLASSNOTREG. I'll leave MK_E_INVALIDEXTENSION // to be compatible with old URLMON (which is harmless). // case MK_E_INVALIDEXTENSION: case REGDB_E_CLASSNOTREG: _SetSearchInfo(pdoh, 0, FALSE, FALSE, FALSE); // reset info #ifdef BUG_EXEC_ON_FAILURE Lexec: // nash:31526 // for various instantiation errors: // - for ie3 we suppress messages and force a ShellExec as a // 2nd try, pretty much always // - for ie4 we should be more selective (nash:31526) #endif #ifdef FEATURE_PICS // For data types that don't have a CLSID, we never get a chance // to block in the CLASSIDAVAILABLE OnProgress notification, so // we have to block here. However, avoid blocking documents such // as HTML which we want to download completely so we can get // ratings strings out of them. // if (!pdoh->_fPicsBlockLate && (pdoh->_PicsProcBase._fbPicsWaitFlags || !pdoh->_PicsProcBase._fPicsAccessAllowed)) { pdoh->_PicsProcBase._fbPicsWaitFlags &= ~(PICS_WAIT_FOR_INDOC | PICS_WAIT_FOR_END); /* make sure we don't expect indoc ratings */ TraceMsg(DM_PICS, "OnStopBinding calling _PicsBlockingDialog, waitflags now %x", (DWORD)pdoh->_PicsProcBase._fbPicsWaitFlags); if (pdoh->_PicsProcBase._PicsBlockingDialog() != IDOK) { TraceMsg(DM_PICS, "OnStopBinding, PICS canceled, calling _CancelPendingNavigation"); pdoh->_CancelPendingNavigation(FALSE); break; } } #endif BeginningTransaction (NULL, NULL, 0, &pwzHeaders); if (_dwBindVerb==BINDVERB_POST) { // This is a POST. Do it use the same moniker (modeless) // // Notes: The ownership of the data in pbinfo will be transfered // to CDownLoad_OpenUIPost. Therefore, we should not call // ReleaseBindInfo(pbinfo) here. // DWORD grfBINDF; // The BINDINFO can not be on the stack since it will be freed by the // download thread. // BINDINFO * pbinfo = (BINDINFO*)LocalAlloc(LPTR, SIZEOF(BINDINFO)); if (!pbinfo) { return E_OUTOFMEMORY; } pbinfo->cbSize = SIZEOF(BINDINFO); GetBindInfo(&grfBINDF, pbinfo); // If our POST was really a redirected POST, it will have // turned into a GET. In this case, we need to release // ownership of the data and pretend like the whole thing // was a GET to start with. if (pbinfo->dwBindVerb==BINDVERB_GET) { WCHAR wszUrl[INTERNET_MAX_URL_LENGTH]; ASSERT(_pszRedirectedURL); SHTCharToUnicode(_pszRedirectedURL, wszUrl, ARRAYSIZE(wszUrl)); IUnknown * punk; HRESULT hresT = pdoh->QueryInterface(IID_IUnknown, (void**)&punk); if (SUCCEEDED(hresT)) { VARIANT varOut = {0}; pdoh->_pmsoctBrowser->Exec(&CGID_ShellDocView, SHDVID_FIREFILEDOWNLOAD, 0, NULL, &varOut); if (V_VT(&varOut) != VT_BOOL || V_BOOL(&varOut) == VARIANT_FALSE) { if (!fAborted) { CDownLoad_OpenUIURL(wszUrl, NULL, pwzHeaders, FALSE /* fSync */, FALSE /* fSaveAs */, pdoh->_fCalledMayOpenSafeDlg, NULL, NULL, NULL, _pszRedirectedURL, pdoh->_uiCP, punk); pwzHeaders = NULL; // ownership is to CDownload now } } punk->Release(); } ReleaseBindInfo(pbinfo); // This one is OK since we did not pass the pbinfo LocalFree(pbinfo); // and we can free it pbinfo = NULL; } else { ASSERT(pbinfo->dwBindVerb==BINDVERB_POST); // Collect the headers associated with this xact IUnknown * punk; HRESULT hresT = pdoh->QueryInterface(IID_IUnknown, (void**)&punk); if (SUCCEEDED(hresT)) { VARIANT varOut = {0}; pdoh->_pmsoctBrowser->Exec(&CGID_ShellDocView, SHDVID_FIREFILEDOWNLOAD, 0, NULL, &varOut); if (V_VT(&varOut) != VT_BOOL || V_BOOL(&varOut) == VARIANT_FALSE) { if (!fAborted) { CDownLoad_OpenUI(pdoh->_pmkCur, _pbc, FALSE /* fSync */, FALSE /* fSaveAs */, pdoh->_fCalledMayOpenSafeDlg /* fSafe */, pwzHeaders, BINDVERB_POST, grfBINDF, pbinfo, _pszRedirectedURL, pdoh->_uiCP, punk); pwzHeaders = NULL; // ownership is to CDownload now } } punk->Release(); } TraceMsg(TF_SHDBINDING, "DOH::OnStopBinding just called CDownLoad_OpenUIPost"); // NOTE: t-gpease 8-18-97 // Do not ReleaseBindInfo(pinfo) because it is used by the download thread. // The thread is responsible for releasing it. } } else { // Otherwise, spawn another thread and get it there. // NOTE: If UnBind gets called then pdoh->_pmkCur will be NULL // and URLMON is most likely returning a bogus error code. So // we'll check the pointer and prevent from blowing up. if (pdoh->_pmkCur) { BOOL fSafe = pdoh->_fCalledMayOpenSafeDlg; IBrowserService * pbs; if (PathIsFilePath(szURL) && SUCCEEDED(pdoh->QueryService(SID_STopFrameBrowser, IID_IBrowserService, (LPVOID *)&pbs))) { DWORD dwFlags; if (SUCCEEDED(pbs->GetFlags(&dwFlags)) && (dwFlags & BSF_NOLOCALFILEWARNING)) { fSafe = TRUE; } pbs->Release(); } IUnknown *punk; HRESULT hresT = pdoh->QueryInterface(IID_IUnknown, (void**)&punk); if (SUCCEEDED(hresT)) { VARIANT varOut = {0}; pdoh->_pmsoctBrowser->Exec(&CGID_ShellDocView, SHDVID_FIREFILEDOWNLOAD, 0, NULL, &varOut); if (V_VT(&varOut) != VT_BOOL || V_BOOL(&varOut) == VARIANT_FALSE) { if (pdoh->_pmsoctBrowser && pdoh->_fWindowOpen) { pdoh->_pmsoctBrowser->Exec(&CGID_Explorer, SBCMDID_CANCELANDCLOSE, 0, NULL, NULL); } if (!fAborted) { CDownLoad_OpenUI(pdoh->_pmkCur, pdoh->_pbcCur, FALSE, FALSE, fSafe, pwzHeaders, NULL, pdoh->_bsc._dwBindf, NULL, _pszRedirectedURL, pdoh->_uiCP, punk, pdoh->_fConfirmed); pwzHeaders = NULL; // ownership is to CDownload now } } punk->Release(); } fAsyncDownload = TRUE; } } if (pwzHeaders) { CoTaskMemFree(pwzHeaders); } break; // URLMON failed to bind because it didn't know what to do with // with this URL. Lets check and see if the Shell should handle // it via a helper app (news:, mailto:, telnet:, etc.) case INET_E_UNKNOWN_PROTOCOL: _SetSearchInfo(pdoh, 0, FALSE, FALSE, FALSE); // reset info { // If we've been redirected, use that URL // if (_pszRedirectedURL) { StrCpyN(szURL, _pszRedirectedURL, ARRAYSIZE(szURL)); } // Here we check to see if it is a URL we really want to shellexecute // so it is handled by helper apps.....else it really is an error if (ShouldShellExecURL(szURL)) { // We can add this to the address bar MRU fAddToMRU = TRUE; // We need to decode this before passing it on to someone. TCHAR szDecodedURL[INTERNET_MAX_URL_LENGTH]; DWORD cchDecodedURL = ARRAYSIZE(szDecodedURL); // REVIEW: NT 319480 IE 54850 - need to append _pszLocation back to pszBadProtoURL... // // I assume the string was escaped when it came from urlmon, so we need // to append it before PrepareURLForExternalApp. // // Note: if the url had been redirected above, _pszLocation has been updated // to the new redirected URL, so we still want to append it. // if (pdoh->_pszLocation) { StrCatBuff(szURL, pdoh->_pszLocation, ARRAYSIZE(szURL)); } PrepareURLForExternalApp(szURL, szDecodedURL, &cchDecodedURL); // PathQuoteSpaces(szDecodedURL); SHELLEXECUTEINFO sei = {0}; sei.cbSize = sizeof(sei); sei.lpFile = szDecodedURL; sei.nShow = SW_SHOWNORMAL; if (!ShellExecuteEx(&sei)) { if(!bSuppressUI) { IE_ErrorMsgBox(pdoh->_psb, pdoh->_hwnd, hrDisplay, szError, szDecodedURL, IDS_CANTSHELLEX, MB_OK | MB_ICONSTOP ); } } // // We want to close the browser window if this is the // very first navigation. // fAsyncDownload = TRUE; } else if ((!bSuppressUI) && (!fCancelAutoSearch)) { _NavigateToErrorPage(ERRORPAGE_SYNTAX, pdoh, FALSE); } break; } case E_ABORT: case HRESULT_FROM_WIN32(ERROR_CANCELLED): _SetSearchInfo(pdoh, 0, FALSE, FALSE, FALSE); // reset info // If the binding was aborted or canceled and this is // a navigation that was delegated from Trident, then // we must fire the FileDownload event so Trident won't // switch the markup. // if (pdoh->_fDelegatedNavigation && pdoh->_pmsoctBrowser) { VARIANT varOut = {0}; pdoh->_pmsoctBrowser->Exec(&CGID_ShellDocView, SHDVID_FIREFILEDOWNLOAD, 0, NULL, &varOut); } break; #ifdef BUG_EXEC_ON_FAILURE case E_NOINTERFACE: // nash:31526 TraceMsg(TF_SHDBINDING, "DOH::OnStopBinding E_NOINTERFACE"); goto Lexec; #endif case INET_E_RESOURCE_NOT_FOUND: case INET_E_DATA_NOT_AVAILABLE: if (!fCancelAutoSearch) { if (_HandleFailedNavigationSearch(&fShouldDisplayError, dwStatusCode, pdoh, hrDisplay, (LPTSTR) &szURL, szError, _pib) != S_OK) { fShouldDisplayError = TRUE; } } else if (!pdoh->_fCanceledByBrowser) { pdoh->_CancelPendingNavigation(FALSE, FALSE); } // intentional fallthrough to default to popup if needed case INET_E_DOWNLOAD_FAILURE: if(IsGlobalOffline()) { fShouldDisplayError = FALSE; break; } // otherwise fall through to do default handling default: { if (fShouldDisplayError) { _SetSearchInfo(pdoh, 0, FALSE, FALSE, FALSE); // reset info if ((!bSuppressUI) && (!fCancelAutoSearch)) { // // If we're in a frame try to navigate in place. This // won't work if we're in a synchronous call // (_fSetTarget). // BOOL fNavigateInPlace = pdoh->_fHaveParentSite && !pdoh->_fSetTarget; _NavigateToErrorPage(ERRORPAGE_DNS, pdoh, fNavigateInPlace); } } } break; } // Tell addressbar to not add this to its mru if (!fAddToMRU) { _DontAddToMRU(pdoh); } // // Prepare for the case where the container keep us visible // after hitting this code (Explorer does, IE doesn't). // pdoh->_fDrawBackground = TRUE; // In the case of quickly jumping to another link, we end up with // a _hwnd being NULL and we were invalidating the desktop. So, // I check for NULL here before calling InvalidateRect. if (pdoh->_hwnd) { InvalidateRect(pdoh->_hwnd, NULL, TRUE); } // Tell the browser to cancel the pending navigation only // if it has not been canceled by the browser itself. // and if the navigation wasn't delegated from the document. // if (!pdoh->_fCanceledByBrowser) { pdoh->_CancelPendingNavigation(fAsyncDownload, FALSE, pdoh->_fDelegatedNavigation); if (pdoh->_fDelegatedNavigation) { IDocNavigate * pDocNavigate; HRESULT hr = E_FAIL; if ( pdoh->_pwb ) { hr = pdoh->_pwb->QueryInterface(IID_PPV_ARG(IDocNavigate, &pDocNavigate)); } if (S_OK == hr) { pDocNavigate->OnReadyStateChange(NULL, READYSTATE_COMPLETE); pDocNavigate->Release(); } } } else { TraceMsg(TF_SHDNAVIGATE|TF_SHDPROGRESS, "DOH::::OnStopBinding not calling _CancelPendingNav"); } } else { BOOL bDidNavigate = FALSE; // Might have redirected to mailto: or some other protocol handled by // plugable protocol that does some magic (eg launch mail program) and // reports OnStopBinding w/o going through OnObjectAvailable! if (NULL == pdoh->_pole && !pdoh->_fCanceledByBrowser) { pdoh->_CancelPendingNavigation(FALSE); } // It is still possible that our Proxy failed to find the server but // gave us HTML. If this is the case, and the user has "find sites" // set, we should go ahead and start trying to do our automatic // navigation stuff. if (dwStatusCode && DO_SEARCH_ON_STATUSCODE(dwStatusCode)) { if (!fCancelAutoSearch) { if (_HandleFailedNavigationSearch(&fShouldDisplayError, dwStatusCode, pdoh, hrDisplay, NULL, szError, _pib) == S_OK) { bDidNavigate = TRUE; } } else if (!pdoh->_fCanceledByBrowser) { pdoh->_CancelPendingNavigation(FALSE, FALSE); } // Note, since the Proxy will have given us HTML in this case, // we will never display an error dialog. } if (!bDidNavigate && !pdoh->_fDocCanNavigate) { _SetSearchInfo(pdoh, 0, FALSE, FALSE, FALSE); // reset info // We can suppress this redundant call to Add to History if DocObject // is MSHTML, since it will report readystate if (!_fBoundToMSHTML && pdoh->_pmkCur) { TCHAR szUrl[MAX_URL_STRING+1]; pdoh->_GetCurrentPage(szUrl,ARRAYSIZE(szUrl)); if (pdoh->_pszLocation) { StrCatBuff(szUrl, pdoh->_pszLocation, ARRAYSIZE(szUrl)); } if (!bSuppressUI) { BOOL fWriteHistory = TRUE; BOOL fSelectHistory = TRUE; if (NULL != pdoh->_pocthf) { MSOCMD rgCmd[] = { { SBCMDID_WRITEHIST, 0 }, { SBCMDID_SELECTHISTPIDL, 0 } }; pdoh->_pocthf->QueryStatus(&CGID_Explorer, ARRAYSIZE(rgCmd), rgCmd, NULL); fWriteHistory = BOOLIFY(rgCmd[0].cmdf & MSOCMDF_ENABLED); fSelectHistory = BOOLIFY(rgCmd[1].cmdf & MSOCMDF_ENABLED); } AddUrlToUrlHistoryStg(szUrl, NULL, pdoh->_pwb, fWriteHistory, fSelectHistory ? pdoh->_pocthf : NULL, pdoh->get_punkSFHistory(), NULL); } } } // if !bDidNavigate } // if failed(hrerror) ... else // Released here because we may need it for OpenUI() w/ POST verb ATOMICRELEASE(_pbc); #ifndef NO_DELEGATION if (_pbscChained) { CHAINMSG("OnStopBinding", hrError); _pbscChained->OnStopBinding(hrError, szError); } #endif ATOMICRELEASE(_pbscChained); ATOMICRELEASE(_pnegotiateChained); pdoh->_ResetStatusBar(); ATOMICRELEASE(pdoh->_pbcCur); if (_pszHeaders) { LocalFree(_pszHeaders); _pszHeaders = NULL; } if (_hszPostData) { GlobalFree(_hszPostData); _hszPostData = NULL; } // NOTES: Guard against last Release by _RevokeObjectParam Release(); return S_OK; } void CDocObjectHost::CDOHBindStatusCallback::AbortBinding(void) { TraceMsg(TF_SHDPROGRESS, "CDOH::CBSC::AbortBinding called _pib=%x", _pib); if (_pib) { TraceMsg(0, "sdv TR AbortBinding Calling _pib->Abort"); // // Notes: OnStopBinding(E_ABORT) will be called from _pib->Abort // HRESULT hresT = _pib->Abort(); TraceMsg(TF_SHDBINDING, "sdv TR AbortBinding Called _pib->Abort (%x)", hresT); // URLMon may call our OnStopBinding asynchronously. ATOMICRELEASE(_pib); CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this); if(pdoh->_dwProgressPos) { pdoh->_ResetStatusBar(); pdoh->_OnSetProgressPos(0, PROGRESS_RESET); } } } // // NavigatesToErrorPage cancels the pending navigation and and navigates to // an internal error page. // void CDocObjectHost::CDOHBindStatusCallback::_NavigateToErrorPage(DWORD dwError, CDocObjectHost* pdoh, BOOL fInPlace) { ASSERT(IsErrorHandled(dwError)); ASSERT(pdoh); // Security: Release the pre-created object because we don't want // anyone to have access to the OM of the navigated error document // if they obtained the reference before the error navigation. // Releasing the reference prevents a parent window from getting keys // to the My Computer zone. pdoh->_ReleaseOleObject(FALSE); pdoh->_ReleasePendingObject(FALSE); // // pdoh->_pmkCur can be NULL if this is a "DNS" error and Unbind has already // been called. // if (pdoh->_pmkCur) { // // Save the url the user attempted to navigate to. It will be used // to refresh the page. // if (pdoh->_pwszRefreshUrl) { OleFree(pdoh->_pwszRefreshUrl); pdoh->_pwszRefreshUrl = NULL; } pdoh->_pmkCur->GetDisplayName(pdoh->_pbcCur, NULL, &pdoh->_pwszRefreshUrl); } if ((NULL == pdoh->_pwszRefreshUrl) || !IsErrorUrl(pdoh->_pwszRefreshUrl)) { // Build the error page url. // TCHAR szErrorUrl[MAX_URL_STRING]; if (fInPlace) { HRESULT hr; hr = MLBuildResURLWrap(TEXT("shdoclc.dll"), HINST_THISDLL, ML_CROSSCODEPAGE, (TCHAR *)c_aErrorUrls[EUIndexFromError(dwError)].pszUrl, szErrorUrl, ARRAYSIZE(szErrorUrl), TEXT("shdocvw.dll")); if (SUCCEEDED(hr)) { // // Navigate to the error page. // IMoniker* pIMoniker; if (SUCCEEDED(MonikerFromString(szErrorUrl, &pIMoniker))) { ASSERT(pIMoniker); #ifdef DEBUG pdoh->_fFriendlyError = TRUE; #endif pdoh->SetTarget(pIMoniker, pdoh->_uiCP, NULL, NULL, NULL, 0); pIMoniker->Release(); } } } else { const WCHAR* const pszFmt = L"#%s"; HRESULT hr; hr = MLBuildResURLWrap(TEXT("shdoclc.dll"), HINST_THISDLL, ML_CROSSCODEPAGE, (TCHAR *)c_aErrorUrls[EUIndexFromError(dwError)].pszUrl, szErrorUrl, ARRAYSIZE(szErrorUrl), TEXT("shdocvw.dll")); if (SUCCEEDED(hr)) { int nLenWritten; // append the # nLenWritten = lstrlen(szErrorUrl); wnsprintf(szErrorUrl + nLenWritten, ARRAYSIZE(szErrorUrl) - nLenWritten, pszFmt, pdoh->_pwszRefreshUrl ? pdoh->_pwszRefreshUrl : L""); // // Cancel the server page and display the internal page instead. // if (!pdoh->_fCanceledByBrowser) pdoh->_CancelPendingNavigation(FALSE); // Turn off the flag in the base browser that // indicates that the view should be reused. // We want a new view in this case. // if ( pdoh->_pwb ) { pdoh->_pwb->SetFlags(NULL, BSF_HTMLNAVCANCELED); } pdoh->_DoAsyncNavigation(szErrorUrl); pdoh->_fCanceledByBrowser = TRUE; } } } return; } // // Check if the user turned off friendly http errors. Default is yes. // BOOL CDocObjectHost::CDOHBindStatusCallback::_DisplayFriendlyHttpErrors() { BOOL fRet; DWORD dwType = REG_SZ; TCHAR szYesOrNo[20]; DWORD cbSize = sizeof(szYesOrNo); if (ERROR_SUCCESS == SHRegGetUSValue(REGSTR_PATH_MAIN, REGSTR_VAL_HTTP_ERRORS, &dwType, (LPVOID)szYesOrNo, &cbSize, FALSE, NULL, 0)) { fRet = StrCmpI(szYesOrNo, L"no"); } else { fRet = TRUE; } return fRet; } // // Error handler // void CDocObjectHost::CDOHBindStatusCallback::_HandleHttpErrors(DWORD dwError, DWORD cbContentLength, CDocObjectHost* pdoh) { // Tell addressbar to not add this to its mru _DontAddToMRU(pdoh); if (IsErrorHandled(dwError)) { pdoh->_fErrorPage = TRUE; // // On a 4XX error display an internal page if the server returned a // page smaller than the threshold value. If the page is larger than // the threshold, display it. // // If the content length is zero assume the server didn't send the // length. In this case take the conservative approach and don't // show our page. // if (cbContentLength != 0 && cbContentLength <= _GetErrorThreshold(dwError)) { if (_DisplayFriendlyHttpErrors()) _NavigateToErrorPage(dwError, pdoh, TRUE); } } return; } // // Informs the address bar to not put this page in its mru // void CDocObjectHost::CDOHBindStatusCallback::_DontAddToMRU(CDocObjectHost* pdoh) { IDockingWindow* pdw = NULL; IOleCommandTarget* poct; if (pdoh->_psp && SUCCEEDED(pdoh->_psp->QueryService(SID_SExplorerToolbar, IID_IDockingWindow, (LPVOID*)&pdw))) { if (SUCCEEDED(pdw->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&poct))) { // Get the URL we were navigating to LPWSTR pszUrl; if (pdoh->_pmkCur && SUCCEEDED(pdoh->_pmkCur->GetDisplayName(pdoh->_pbcCur, NULL, &pszUrl))) { LBSTR::CString strDisplay( pszUrl ); VARIANT varURL = {0}; varURL.vt = VT_BSTR; varURL.bstrVal = strDisplay; poct->Exec(&CGID_Explorer, SBCMDID_ERRORPAGE, 0, &varURL, NULL); OleFree(pszUrl); } poct->Release(); } pdw->Release(); } } // // Tells the addressbar that we are autosearching so that it can update // the pending url in its mru // void CDocObjectHost::CDOHBindStatusCallback::_UpdateMRU(CDocObjectHost* pdoh, LPCWSTR pszUrl) { IDockingWindow* pdw = NULL; IOleCommandTarget* poct; if (pdoh->_psp && SUCCEEDED(pdoh->_psp->QueryService(SID_SExplorerToolbar, IID_IDockingWindow, (LPVOID*)&pdw))) { if (SUCCEEDED(pdw->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&poct))) { // Copy url to stack allocated bstr LBSTR::CString strDisplay( pszUrl ); VARIANT varURL = {0}; varURL.vt = VT_BSTR; varURL.bstrVal = strDisplay; poct->Exec(&CGID_Explorer, SBCMDID_AUTOSEARCHING, 0, &varURL, NULL); poct->Release(); } pdw->Release(); } } // // S_OK means we successfully did a navigation // S_FALSE means that we did everything ok, but did not navigate // E_* means some internal api failed. // HRESULT CDocObjectHost::CDOHBindStatusCallback::_HandleFailedNavigationSearch( LPBOOL pfShouldDisplayError, DWORD dwStatusCode, CDocObjectHost * pdoh, HRESULT hrDisplay, TCHAR * szURL, LPCWSTR szError, IBinding * pib, BOOL fAddMRU, /* = TRUE */ BOOL fFromTrident /* = FALSE */) { DWORD dwSearchForExtensions = NO_SUFFIXES; DWORD dwDo404Search = PROMPTSEARCH; BOOL bAskUser = TRUE; // rely on init BOOL bDoSearch = FALSE; // rely on init HRESULT hres = S_FALSE; BOOL bSuppressUI = FALSE; BOOL bFrameIsOffline = FALSE; BOOL bPrepareForSearch = FALSE; DWORD dwSuffixIndex = 0; BOOL bAllowSearch = FALSE; BOOL bContinueSearch = FALSE; BOOL bSentToEngine = FALSE; BOOL bOnProxy = FALSE; TCHAR szSearchFormatStr[MAX_SEARCH_FORMAT_STRING]; DWORD dwSearchStyle = 3; // "display search results and navigate to the most likely site" ASSERT(pdoh); #define SAFETRACE(psz) (psz ? psz : TEXT("")) TraceMsg(TF_SHDNAVIGATE, "DOH::BSC::_HFNS() entered status = %d, url = %s, pib = %X", dwStatusCode, SAFETRACE(szURL) , pib); if (FAILED(GetSearchKeys(pdoh->_psp, &dwSearchStyle, &dwSearchForExtensions, &dwDo404Search))) { return E_FAIL; } TraceMsg(TF_SHDNAVIGATE, "DOH::BSC::_HFNS() dwSearch = %d, do404 = %d", dwSearchForExtensions, dwDo404Search); // Get any persistent information from the last request VARIANT varURL = {0}; _GetSearchInfo(pdoh->_psp, &dwSuffixIndex, &bAllowSearch, &bContinueSearch, &bSentToEngine, &varURL); // See if window.external.autoscan() was called BOOL fAutoScan = (varURL.vt == VT_BSTR); TraceMsg(TF_SHDNAVIGATE, "DOH::BSC::_HFNS() index = %d, allow = %d, cont = %d, sent = %d", dwSuffixIndex, bAllowSearch, bContinueSearch, bSentToEngine); // Why not use the cached value? // pdoh->_GetOfflineSilent(&bFrameIsOffline, &bSuppressUI); bFrameIsOffline = _bFrameIsOffline ? TRUE : FALSE; bSuppressUI = (_bFrameIsSilent || _IsDesktopItem(pdoh)) ? TRUE : FALSE; // if we are at the end of the extension list, turn off extensions BOOL fAutoSearching = FALSE; if (dwSearchForExtensions) { if (dwSuffixIndex == 0 && dwSearchStyle != 0) { StrCpyN(szSearchFormatStr, L"? %s", ARRAYSIZE(szSearchFormatStr)); fAutoSearching = TRUE; } else if (GetSearchFormatString(dwSuffixIndex, szSearchFormatStr, sizeof(szSearchFormatStr)) != ERROR_SUCCESS) { dwSearchForExtensions = DONE_SUFFIXES; StrCpyN(szSearchFormatStr, TEXT("%s"), ARRAYSIZE(szSearchFormatStr)); } } else { dwSearchForExtensions = DONE_SUFFIXES; } // don't try a 404 srch if we are still trying suffixes if (dwSearchForExtensions == SCAN_SUFFIXES) dwDo404Search = NEVERSEARCH; { DWORD dwOptions; if (SUCCEEDED(_GetRequestFlagFromPIB(pib, &dwOptions))) { if (dwOptions & INTERNET_REQFLAG_VIA_PROXY) { bOnProxy = TRUE; } } else { TraceMsg(TF_SHDNAVIGATE, "DOH::BSC::_HFNS() QI to IWinInetInfo failed"); } } TraceMsg(TF_SHDNAVIGATE, "DOH::BSC::_HFNS() search = %d, do404 = %d, onproxy = %d, szSearch = %s", dwSearchForExtensions, dwDo404Search, bOnProxy, SAFETRACE(szSearchFormatStr)); // Prepare to do an automatic search if the navigation failed // and we think a search might be valuable. // These cases are: // (1) if the previous navigation was search-generated (bContinue) // (2) the user allows searching (bAllow) // (3) we are searching for extensions or autosearching // (4) this is a status code we allow searching for // (5) if over proxy, continue searching even on 404 // Note: 404 is special; it is the case that most servers return this if // the documnet is not there, but Proxies also return this if the server // was not found - a conditon which normally makes us search. This means // that a 404 over proxy actually causes a search to occur, which is not // what we want. // Is there any way I can tell the difference? bPrepareForSearch = ((bContinueSearch || (bAllowSearch)) && (fAutoScan || SHOULD_DO_SEARCH(dwSearchForExtensions, dwDo404Search)) && DO_SEARCH_ON_STATUSCODE(dwStatusCode) && (!bOnProxy || pdoh->_fDocCanNavigate || (dwStatusCode == HTTP_STATUS_NOT_FOUND))); if (bPrepareForSearch) { TraceMsg(TF_SHDNAVIGATE, "DOH::BSC::_HFNS() Preparing for Search..."); HRESULT hr = S_OK; // If we don't have the url we are searching, get it from the addressbar if (!fAutoScan) hr = _GetSearchString(pdoh->_psp, &varURL); if (S_OK!=hr && pdoh->_fDocCanNavigate) { hr = VariantCopy(&varURL, &pdoh->_varUserEnteredUrl); } // If we have completed the autoscan, see if there is a special error page that // we should display. VARIANT varScanFailure = {0}; if (SUCCEEDED(hr) && dwSearchForExtensions == DONE_SUFFIXES && SUCCEEDED(_GetScanFailureUrl(pdoh->_psp, &varScanFailure))) { bDoSearch = TRUE; } else if (SUCCEEDED(hr) && (dwSearchForExtensions == SCAN_SUFFIXES || dwDo404Search == ALWAYSSEARCH)) { bDoSearch = TRUE; } else { bDoSearch = FALSE; } bAskUser = FALSE; TraceMsg(TF_SHDNAVIGATE, "DOH::BSC::_HFNS() typedurl = %s, ask = %d, dosearch = %d", varURL.bstrVal, bAskUser, bDoSearch); // Don't prompt user if there is an extension, since we are going to // not scan anyway. if (bDoSearch) { PARSEDURL pu; pu.cbSize = SIZEOF(PARSEDURL); if (ParseURL(varURL.bstrVal, &pu) == URL_E_INVALID_SYNTAX) { // only if this is not a valid URL, should we try to do this searching // but try to avoid the case of typos like http;//something.something.com // The malformed URL case if (!fAutoSearching && (//StrChrI(varURL.bstrVal, L'.') || StrChrI(varURL.bstrVal, L'/') || StrChrI(varURL.bstrVal, L' ')) ) { bAskUser = FALSE; bDoSearch = FALSE; } } else { bAskUser = FALSE; bDoSearch = FALSE; } } TCHAR szT[MAX_URL_STRING + SEARCHPREFIXLENGTH]; DWORD cchT = SIZECHARS(szT); // Bug 35354 has been resolved "not repro" because the dialog below // currently cannot ever be displayed (there is no way for bAskUser to // be true in the following conditional). If that changes, then that bug // needs to get fixed. if (bAskUser) { PrepareURLForDisplay(varURL.bstrVal, szT, &cchT); // If we ask the user, make sure we don't display another // error dialog. *pfShouldDisplayError = FALSE; // S_OK means we handled any popups; if we return an error, // the caller may display an error dialog hres = S_OK; if (!bSuppressUI && IDYES == IE_ErrorMsgBox(NULL, pdoh->_hwnd, hrDisplay, szError, szT, IDS_CANTFINDURL, MB_YESNO|MB_ICONSTOP)) { bDoSearch = TRUE; } else { _SetSearchInfo(pdoh, 0, FALSE, FALSE, FALSE); // reset info bDoSearch = FALSE; } } if (bDoSearch) { if (dwSearchForExtensions && dwSearchForExtensions != DONE_SUFFIXES) { wnsprintf(szT, ARRAYSIZE(szT), szSearchFormatStr, varURL.bstrVal); if (!fAutoSearching) { _ValidateURL(szT, UQF_DEFAULT); } if (fAddMRU) _UpdateMRU(pdoh, szT); } else if (VT_BSTR == varScanFailure.vt && NULL != varScanFailure.bstrVal) { StrCpyN(szT, varScanFailure.bstrVal, ARRAYSIZE(szT)); _ValidateURL(szT, UQF_DEFAULT); _DontAddToMRU(pdoh); } else if (dwDo404Search) { // add the search prefix StrCpyN(szT, TEXT("? "), ARRAYSIZE(szT)); StrCatBuff(szT, varURL.bstrVal, ARRAYSIZE(szT)); _DontAddToMRU(pdoh); } else { ASSERT(0); } if (dwSearchForExtensions && dwSearchForExtensions != DONE_SUFFIXES) _SetSearchInfo(pdoh, ++dwSuffixIndex, FALSE, TRUE, FALSE); else if (dwDo404Search) _SetSearchInfo(pdoh, dwSuffixIndex, FALSE, FALSE, TRUE); else _SetSearchInfo(pdoh, 0, FALSE, FALSE, FALSE); // If we're called from Trident (fFromTrident == TRUE), then we're going to call // IHTMLPrivateWindow::SuperNavigate(). In that case, the call to _CancelPendingNavigation // below needs to be synchronous. However, if we're going to call _DoAsyncNavigation, // then the call to _CancelPendingNavigation needs to remain asynchronous. // if (!pdoh->_fCanceledByBrowser) pdoh->_CancelPendingNavigation(FALSE, fFromTrident); TraceMsg(TF_SHDNAVIGATE, "DOH::BSC::_HFNS() Doing search on %s", szT); DWORD cchT = SIZECHARS(szT); // // if we can find a search context living in a host somewhere, // then we need to pass that into ParseUrlFromOutsideSource // because it'll use it to customize the behavior of // the search hooks if a search ends up happening // ISearchContext * pSC = NULL; pdoh->QueryService(SID_STopWindow, IID_ISearchContext, (void **)&pSC); ParseURLFromOutsideSourceWithContextW(szT, szT, &cchT, NULL, pSC); if (pSC != NULL) { pSC->Release(); } if (fFromTrident) { BSTR bstrUrl = SysAllocString(szT); IHTMLPrivateWindow * pPrivWindow = NULL; ASSERT(pdoh->_fDocCanNavigate); ASSERT(pdoh->_pHTMLWindow); // The navigation state is already reset by cancelpending navigation // causing either trident to cancel pending navigation or by OnStopBinding /* if (pdoh->_pwb) pdoh->_pwb->SetNavigateState(BNS_NORMAL); */ hres = pdoh->_pHTMLWindow->QueryInterface(IID_IHTMLPrivateWindow, (void**)&pPrivWindow); if (SUCCEEDED(hres)) { hres = pPrivWindow->SuperNavigate(bstrUrl, NULL, NULL, NULL, NULL, NULL, 0); pPrivWindow->Release(); } SysFreeString(bstrUrl); } else { pdoh->_DoAsyncNavigation(szT); } pdoh->_fCanceledByBrowser = TRUE; *pfShouldDisplayError = FALSE; // Don't display another dialog hres = S_OK; // we did a navigate } VariantClear(&varScanFailure); } else if (bSentToEngine && !bSuppressUI) { *pfShouldDisplayError = FALSE; _SetSearchInfo(pdoh, 0, FALSE, FALSE, FALSE); IE_ErrorMsgBox(NULL, pdoh->_hwnd, hrDisplay, szError, szURL, IDS_CANTFINDSEARCH, MB_OK|MB_ICONSTOP); hres = S_OK; } VariantClear(&varURL); return hres; } // _HandleFailedNavigationSearch()