3584 lines
119 KiB
C++
3584 lines
119 KiB
C++
|
#include "priv.h"
|
||
|
#include "iehelpid.h"
|
||
|
#include "bindcb.h"
|
||
|
#include "winlist.h"
|
||
|
#include "droptgt.h"
|
||
|
#include <mshtml.h> // CLSID_HTMLDocument
|
||
|
#include "resource.h"
|
||
|
#include <htmlhelp.h>
|
||
|
#include <prsht.h>
|
||
|
#include <inetcpl.h>
|
||
|
#include <optary.h>
|
||
|
#include "shdocfl.h"
|
||
|
#include "interned.h" // IHTMLPrivateWindow
|
||
|
|
||
|
#ifdef FEATURE_PICS
|
||
|
#include <shlwapi.h>
|
||
|
#include <ratings.h>
|
||
|
#endif
|
||
|
|
||
|
#include "dochost.h"
|
||
|
|
||
|
#include <mluisupp.h>
|
||
|
|
||
|
#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[10];
|
||
|
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('/') &&
|
||
|
szDisplayName[iResStart] != TEXT('\0'))
|
||
|
{
|
||
|
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(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, MAX_URL_STRING);
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CDocObjectHost::CDOHBindStatusCallback::_HandleSelfAssociate(void)
|
||
|
{
|
||
|
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
|
||
|
HRESULT hres;
|
||
|
IPersistMoniker* ppmk;
|
||
|
hres = pdoh->_CoCreateHTMLDocument(IID_IPersistMoniker, (LPVOID*)&ppmk);
|
||
|
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
BIND_OPTS bindopts;
|
||
|
bindopts.cbStruct = sizeof(BIND_OPTS);
|
||
|
hres = _pbc->GetBindOptions(&bindopts);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
hres = ppmk->Load(FALSE, pdoh->_pmkCur, _pbc, bindopts.grfMode);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
ASSERT(NULL==pdoh->_pole);
|
||
|
hres = ppmk->QueryInterface(IID_IOleObject, (LPVOID*)&pdoh->_pole);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
pdoh->_InitOleObject();
|
||
|
|
||
|
TraceMsg(DM_SELFASC, "DOH::_HandleSelfAssociate self-association is working");
|
||
|
pdoh->_Navigate();
|
||
|
pdoh->_SetUpTransitionCapability();
|
||
|
_UpdateSSLIcon();
|
||
|
} else {
|
||
|
TraceMsg(DM_WARNING, "DOH::_HandleSelfAssociate ppmk->QI(IOleObject) failed (%x)", hres);
|
||
|
}
|
||
|
} else {
|
||
|
TraceMsg(DM_WARNING, "DOH::_HandleSelfAssociate ppmk->Load failed (%x)", hres);
|
||
|
}
|
||
|
} else {
|
||
|
TraceMsg(DM_WARNING, "DOH::_HandleSelfAssociate _pbc->GetBindOptions failed (%x)", hres);
|
||
|
}
|
||
|
ppmk->Release();
|
||
|
} else {
|
||
|
TraceMsg(DM_WARNING, "DOH::_HandleSelfAssociate CoCreateInst failed (%x)", hres);
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
#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 #<refresh URL>
|
||
|
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()
|