You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1665 lines
56 KiB
1665 lines
56 KiB
#include "priv.h"
|
|
#include "resource.h"
|
|
#include "hlframe.h"
|
|
#include "bindcb.h"
|
|
#include "winlist.h"
|
|
#include "iface.h"
|
|
#include "shdocfl.h"
|
|
#include <optary.h>
|
|
#include <mluisupp.h>
|
|
|
|
#define DM_SHELLEXECOBJECT 0x80000000
|
|
|
|
|
|
// flags for SHDVID_DOCFAMILYCHARSET communication
|
|
#define DFC_URLCHARSET 1
|
|
|
|
#ifdef FEATURE_PICS
|
|
#include "dochost.h" /* for IID_IsPicsBrowser */
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
extern DWORD g_dwPerf;
|
|
#endif
|
|
|
|
#define DM_HLINKTRACE DM_TRACE
|
|
|
|
#define DM_WEBCHECKDRT 0
|
|
#define JMPMSG(psz, psz2) TraceMsg(0, "shlf TR-CDOV::%s %s", psz, psz2)
|
|
#define JMPMSG2(psz, x) TraceMsg(0, "shlf TR-CDOV::%s %x", psz, x)
|
|
#define DOFMSG(psz) TraceMsg(0, "shlf TR-DOF::%s", psz)
|
|
#define DOFMSG2(psz, x) TraceMsg(0, "shlf TR-DOF::%s %x", psz, x)
|
|
#define URLMSG(psz) TraceMsg(0, "shlf TR-DOF::%s", psz)
|
|
#define URLMSG2(psz, x) TraceMsg(0, "shlf TR-DOF::%s %x", psz, x)
|
|
#define URLMSG3(psz, x, y) TraceMsg(0, "shlf TR-DOF::%s %x %x", psz, x, y)
|
|
#define BSCMSG(psz, i, j) TraceMsg(0, "shlf TR-BSC::%s %x %x", psz, i, j)
|
|
#define BSCMSG3(psz, i, j, k) TraceMsg(0, "shlf TR-BSC::%s %x %x %x", psz, i, j, k)
|
|
#define BSCMSGS(psz, sz) TraceMsg(0, "shlf TR-BSC::%s %s", psz, sz)
|
|
#define OIPSMSG(psz) TraceMsg(0, "shlf TR-OIPS::%s", psz)
|
|
#define OIPSMSG3(psz, sz, p) TraceMsg(0, "shlf TR-OIPS::%s %s,%x", psz, sz,p)
|
|
#define REFMSG0(psz) TraceMsg(0, "shlf TR-CDOV::%s", psz)
|
|
#define REFMSG(psz, cRef) TraceMsg(0, "shlf TR-CDOV::%s new _cRef==%d", psz, cRef)
|
|
#define REFMSG2(psz, if, cRef) TraceMsg(0, "shlf TR-CDOV::%s(%s) new _cRef==%d", psz, if, cRef)
|
|
#define VIEWMSG(psz) TraceMsg(0, "shlf TR CDOV::%s", psz)
|
|
#define VIEWMSG2(psz,xx) TraceMsg(0, "shlf TR CDOV::%s %x", psz,xx)
|
|
#define CACHEMSG(psz, d) TraceMsg(0, "shlf TR CDocObjectCtx::%s %d", psz, d)
|
|
#define HFRMMSG(psz) TraceMsg(TF_SHDNAVIGATE, "shlf HFRM::%s", psz)
|
|
#define HFRMMSG2(psz, x, y) TraceMsg(TF_SHDNAVIGATE, "shlf HFRM::%s %x %x", psz, x, y)
|
|
#define MNKMSG(psz, psz2) TraceMsg(0, "shlf MNK::%s (%s)", psz, psz2)
|
|
#define SERVMSG(psz, x, y) TraceMsg(0, "shlf SERV::%s %x %x", psz, x, y)
|
|
|
|
#define KEY_BINDCONTEXTPARAM _T("BIND_CONTEXT_PARAM")
|
|
#define SZ_DWNBINDINFO_OBJECTPARAM _T("__DWNBINDINFO")
|
|
|
|
BOOL g_fHlinkDLLLoaded = FALSE; // must be per-process
|
|
|
|
STDAPI HlinkFrameNavigate(DWORD grfHLNF, IBindCtx *pbc,
|
|
IBindStatusCallback *pibsc,
|
|
IHlink* pihlNavigate,
|
|
IHlinkBrowseContext *pihlbc);
|
|
STDAPI HlinkFrameNavigateNHL(DWORD grfHLNF, IBindCtx *pbc,
|
|
IBindStatusCallback *pibsc,
|
|
LPCWSTR pszTargetFrame,
|
|
LPCWSTR pszUrl,
|
|
LPCWSTR pszLocation);
|
|
|
|
// IHlinkFrame members
|
|
HRESULT CIEFrameAuto::SetBrowseContext(IHlinkBrowseContext *pihlbc)
|
|
{
|
|
if (pihlbc)
|
|
pihlbc->AddRef();
|
|
|
|
if (_phlbc)
|
|
{
|
|
if (_dwRegHLBC)
|
|
{
|
|
_phlbc->Revoke(_dwRegHLBC);
|
|
_dwRegHLBC = 0;
|
|
}
|
|
_phlbc->Release();
|
|
}
|
|
|
|
_phlbc = pihlbc;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT CIEFrameAuto::GetBrowseContext(IHlinkBrowseContext **ppihlbc)
|
|
{
|
|
TraceMsg(0, "shlf TR ::GetBrowseContext called");
|
|
|
|
*ppihlbc = _phlbc;
|
|
|
|
if (_phlbc)
|
|
{
|
|
_phlbc->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
void CIEFrameAuto::_SetPendingNavigateContext(IBindCtx *pbc, IBindStatusCallback *pibsc)
|
|
{
|
|
if (_pbscPending)
|
|
{
|
|
_pbscPending->Release();
|
|
_pbscPending = NULL;
|
|
}
|
|
|
|
if (_pbcPending)
|
|
{
|
|
_pbcPending->Release();
|
|
_pbcPending = NULL;
|
|
}
|
|
|
|
if (pibsc)
|
|
{
|
|
_pbscPending = pibsc;
|
|
_pbscPending->AddRef();
|
|
}
|
|
|
|
if (pbc)
|
|
{
|
|
// as long as we are cacheing the pending BindCtx, if it specifies
|
|
// a shortcut URL we need to cache that too. (IE:98431)
|
|
IUnknown * pUnk = NULL;
|
|
IHtmlLoadOptions * pHtmlLoadOptions = NULL;
|
|
|
|
_pbcPending = pbc;
|
|
_pbcPending->AddRef();
|
|
|
|
pbc->GetObjectParam(_T("__HTMLLOADOPTIONS"), &pUnk);
|
|
if (pUnk)
|
|
{
|
|
pUnk->QueryInterface(IID_IHtmlLoadOptions, (void **) &pHtmlLoadOptions);
|
|
|
|
if (pHtmlLoadOptions)
|
|
{
|
|
TCHAR achCacheFile[MAX_PATH+1];
|
|
ULONG cchCacheFile = ARRAYSIZE(achCacheFile)-1;
|
|
|
|
memset(&achCacheFile, 0, (cchCacheFile+1)*sizeof(TCHAR) );
|
|
|
|
// now determine if this is a shortcut-initiated load
|
|
pHtmlLoadOptions->QueryOption(HTMLLOADOPTION_INETSHORTCUTPATH,
|
|
&achCacheFile,
|
|
&cchCacheFile);
|
|
|
|
if (_pwszShortcutPathPending)
|
|
LocalFree(_pwszShortcutPathPending);
|
|
|
|
_pwszShortcutPathPending = StrDup(achCacheFile);
|
|
|
|
pHtmlLoadOptions->Release();
|
|
}
|
|
|
|
pUnk->Release();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// NavigateContext is a set of parameters passed from one CIEFrameAuto
|
|
// to another.
|
|
//
|
|
void CIEFrameAuto::_ActivatePendingNavigateContext()
|
|
{
|
|
if (_pbsc)
|
|
{
|
|
_pbsc->Release();
|
|
_pbsc = NULL;
|
|
}
|
|
|
|
if (_pbc)
|
|
{
|
|
_pbc->Release();
|
|
_pbc = NULL;
|
|
}
|
|
|
|
if (_pwszShortcutPath)
|
|
{
|
|
LocalFree(_pwszShortcutPath);
|
|
_pwszShortcutPath = NULL;
|
|
}
|
|
|
|
if (_pbscPending)
|
|
{
|
|
_pbsc = _pbscPending;
|
|
_pbscPending = NULL;
|
|
}
|
|
|
|
if (_pbcPending)
|
|
{
|
|
_pbc = _pbcPending;
|
|
_pbcPending = NULL;
|
|
}
|
|
|
|
if (_pwszShortcutPathPending)
|
|
{
|
|
_pwszShortcutPath = _pwszShortcutPathPending;
|
|
_pwszShortcutPathPending = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
// Called to guarantee a newly created HLinkFrame's window is
|
|
// visible after the navigate.
|
|
HRESULT ShowHlinkFrameWindow(IUnknown *pUnkTargetHlinkFrame)
|
|
{
|
|
IWebBrowserApp* pdie;
|
|
HRESULT hres = pUnkTargetHlinkFrame->QueryInterface(IID_PPV_ARG(IWebBrowserApp, &pdie));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
pdie->put_Visible(TRUE);
|
|
pdie->Release();
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CIEFrameAuto::_NavigateMagnum(DWORD grfHLNF, IBindCtx *pbc, IBindStatusCallback *pibsc, LPCWSTR pszTargetName, LPCWSTR pszUrl, LPCWSTR pszLocation, IHlink *pihlNavigate, IMoniker *pmkTarget)
|
|
{
|
|
HRESULT hres = NOERROR;
|
|
HFRMMSG2("Navigate called", grfHLNF, pihlNavigate);
|
|
BOOL fNavigateForReal = pszUrl || (pihlNavigate && (pihlNavigate != (IHlink*)-1));
|
|
|
|
_fSuppressHistory = _psbProxy != _psb; // no history for search band, etc
|
|
_fSuppressSelect = _psbProxy != _psb; // no need to record select pidl
|
|
if (grfHLNF != (DWORD)-1)
|
|
{
|
|
if (SHHLNF_WRITENOHISTORY & grfHLNF)
|
|
{
|
|
_fSuppressHistory = TRUE;
|
|
}
|
|
if (SHHLNF_NOAUTOSELECT & grfHLNF)
|
|
{
|
|
_fSuppressSelect = TRUE;
|
|
}
|
|
}
|
|
|
|
if (pbc == NULL && pibsc == NULL && pihlNavigate == NULL && pszUrl == NULL)
|
|
{
|
|
//
|
|
// This is a private interface so that mshtml can do navigation
|
|
// if it is hosted by the shell. When IHlinkBrowseContext is implemented
|
|
// in the shell this special code can be removed and the associated
|
|
// code in mshtml that calls Navigate with these special parameters
|
|
// can be removed so that it just goes through the
|
|
// IHlinkBrowseContext->SetCurrentHlink interface.
|
|
//
|
|
// We also use this private mechanism to release the navigation
|
|
// context with grfHLNF==0.
|
|
//
|
|
|
|
switch (grfHLNF&~(SHHLNF_WRITENOHISTORY|SHHLNF_NOAUTOSELECT))
|
|
{
|
|
case HLNF_NAVIGATINGBACK:
|
|
hres = _BrowseObject(PIDL_LOCALHISTORY, SBSP_SAMEBROWSER|SBSP_NAVIGATEBACK);
|
|
break;
|
|
|
|
case HLNF_NAVIGATINGFORWARD:
|
|
hres = _BrowseObject(PIDL_LOCALHISTORY, SBSP_SAMEBROWSER|SBSP_NAVIGATEFORWARD);
|
|
break;
|
|
|
|
case 0:
|
|
_ActivatePendingNavigateContext();
|
|
break;
|
|
|
|
default:
|
|
hres = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
#ifdef FEATURE_PICS
|
|
/* As part of checking ratings, the PICS code will silently download the
|
|
* root document of a site to look for rating labels in it. If that's a
|
|
* frameset page, Trident will create OCXs for the subframes and try to
|
|
* navigate them, which will invoke ratings checks for them and cause
|
|
* infinite recursion. So here we check to see if our top-level browser
|
|
* is really this PICS download, and if it is, we don't do any navigation.
|
|
*/
|
|
IUnknown *punkPics;
|
|
if (SUCCEEDED(QueryService(SID_STopLevelBrowser, IID_IsPicsBrowser, (void **)&punkPics)))
|
|
{
|
|
punkPics->Release();
|
|
return S_OK;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If we've got this call while we are busy (EnableModeless is FALSE),
|
|
// we should just bail here (instead of doing somthing and let _JumpTo
|
|
// call fail.
|
|
//
|
|
// This can happen if someone has a window.location="foobar.htm" in their unload
|
|
// event handler.
|
|
if (fNavigateForReal && !(grfHLNF & HLNF_OPENINNEWWINDOW))
|
|
{
|
|
// If _pbs is NULL, it is bad news; we can't navigate.
|
|
// An allowable reason for this condition is that someone has called CIEFrameAuto::Quit()
|
|
// and we are in the process of shutting down.
|
|
//
|
|
if (_pbs == NULL)
|
|
{
|
|
if (_fQuitInProgress)
|
|
{
|
|
TraceMsg(TF_WARNING, "CIEFrameAuto::_NavigateMagnum quitting due to browser closing.");
|
|
return S_OK;
|
|
}
|
|
TraceMsg(TF_WARNING, "CIEFrameAuto::_NavigateMagnum _pbs is NULL, but we are not shutting down.");
|
|
return E_FAIL;
|
|
}
|
|
|
|
// If we have a _pbs but the browser says that it can't navigate now, then return S_FALSE.
|
|
//
|
|
else if (_pbs->CanNavigateNow() != S_OK)
|
|
{
|
|
TraceMsg(TF_WARNING, "CIEFrameAuto::Navigate CanNavigateNow returns non S_OK, bail out.");
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// This Navigate method is not re-entrant (because of _SetPendingNavigateContext)
|
|
//
|
|
if (_fBusy)
|
|
{
|
|
TraceMsg(DM_WARNING, "CIEA::Navigate re-entered. Returning E_FAIL");
|
|
return E_FAIL;
|
|
}
|
|
_fBusy = TRUE;
|
|
|
|
//
|
|
// HACK: To let Webcheck DRT go.
|
|
//
|
|
if (fNavigateForReal && !(grfHLNF & HLNF_OPENINNEWWINDOW))
|
|
{
|
|
TraceMsg(DM_WEBCHECKDRT, "CIFA::Navigate calling _CancelPendingNavigation");
|
|
VARIANT var = { 0 };
|
|
var.vt = VT_I4;
|
|
var.lVal = TRUE; // synchronous
|
|
|
|
_CancelPendingNavigation(&var);
|
|
}
|
|
|
|
if (pszUrl && SHRestricted2(REST_NOFILEURL, NULL, 0) && PathIsFilePath(pszUrl))
|
|
{
|
|
TCHAR szPath[MAX_URL_STRING];
|
|
SHUnicodeToTChar(pszUrl, szPath, ARRAYSIZE(szPath));
|
|
MLShellMessageBox(NULL, MAKEINTRESOURCE(IDS_SHURL_ERR_PARSE_NOTALLOWED),
|
|
szPath, MB_OK | MB_ICONERROR, szPath);
|
|
|
|
_fBusy = FALSE;
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
|
|
_SetPendingNavigateContext(pbc, pibsc);
|
|
|
|
#ifdef DEBUG
|
|
g_dwPerf = GetCurrentTime();
|
|
|
|
#endif
|
|
|
|
if (pihlNavigate == (IHlink*)-1)
|
|
{
|
|
//
|
|
// HACK: -1 means "release the navigation state".
|
|
// CDocObjectHost::_CancelPendingNavigation is the only caller.
|
|
// It Exec's SBCMDID_CANCELNAVIGATION which will asynchronously
|
|
// cancel the pending navigation. Therefore, we no longer need
|
|
// to call _CancelPendingNavigation here. (SatoNa)
|
|
//
|
|
// _CancelPendingNavigation();
|
|
}
|
|
else if (pihlNavigate || pszUrl)
|
|
{
|
|
hres = S_OK;
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if ((grfHLNF & HLNF_EXTERNALNAVIGATE) && (grfHLNF & HLNF_NAVIGATINGBACK))
|
|
GoBack();
|
|
else if ((grfHLNF & HLNF_EXTERNALNAVIGATE) && (grfHLNF & HLNF_NAVIGATINGFORWARD))
|
|
GoForward();
|
|
else
|
|
{
|
|
hres = _JumpTo(pbc,(LPWSTR) pszLocation, grfHLNF, pibsc, pihlNavigate, pszTargetName, pszUrl);
|
|
if (FAILED(hres))
|
|
{
|
|
TraceMsg(DM_ERROR, "IEAuto::Navigate _JumpTo failed %x", hres);
|
|
}
|
|
}
|
|
if (pihlNavigate)
|
|
{
|
|
//
|
|
// Hopefully, we'll come up with a clean solution to
|
|
// solve this problem nicely. I made a proposal to NatBro/SriniK
|
|
// that CreateHlink will CoCreateInstance IHlink so that OLE
|
|
// LoadLibrary it and maintains it as an InProc server. (SatoNa)
|
|
//
|
|
// HACK: If we AddRef to IHlink, we need to make it sure that
|
|
// HLINK.DLL is stay loaded even though the DocObject InProc
|
|
// server (that implicitly links to HLINK.DLL) is unloaded.
|
|
//
|
|
if (!g_fHlinkDLLLoaded)
|
|
{
|
|
LoadLibrary(TEXT("hlink.dll"));
|
|
g_fHlinkDLLLoaded = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(DM_ERROR, "CIEFA::Nav phl->GetMonRef failed %x", hres);
|
|
}
|
|
}
|
|
|
|
_fBusy = FALSE;
|
|
|
|
HFRMMSG2("Navigate returning", hres, 0);
|
|
|
|
if (SUCCEEDED(hres) && (pihlNavigate != (IHlink*)-1))
|
|
{
|
|
if (grfHLNF & HLNF_EXTERNALNAVIGATE)
|
|
{
|
|
HWND hwndFrame;
|
|
_psb->GetWindow(&hwndFrame);
|
|
|
|
if (_phlbc)
|
|
{
|
|
// if we have a browse context, then we're navigating from it and
|
|
// we should size our window to match it.
|
|
HLBWINFO hlbwi;
|
|
|
|
hlbwi.cbSize = SIZEOF(hlbwi);
|
|
if (SUCCEEDED(_phlbc->GetBrowseWindowInfo(&hlbwi)) &&
|
|
(hlbwi.grfHLBWIF & HLBWIF_HASFRAMEWNDINFO))
|
|
{
|
|
WINDOWPLACEMENT wp;
|
|
|
|
wp.length = sizeof(WINDOWPLACEMENT);
|
|
GetWindowPlacement(hwndFrame, &wp);
|
|
wp.rcNormalPosition = hlbwi.rcFramePos;
|
|
wp.showCmd = (hlbwi.grfHLBWIF & HLBWIF_FRAMEWNDMAXIMIZED)
|
|
? SW_SHOWMAXIMIZED : SW_SHOWNORMAL;
|
|
|
|
// This is not broken in AOL because this
|
|
// is an external navigate (word has cocreateinstance()d
|
|
// Internet.Explorer and navigated it.
|
|
//
|
|
SetWindowPlacement(hwndFrame, &wp);
|
|
}
|
|
|
|
// Register the hlinkframe interface with the browse context, if it has not already
|
|
// been registered
|
|
if (_dwRegHLBC == 0)
|
|
_phlbc->Register(0, (IHlinkFrame *) this, pmkTarget, &_dwRegHLBC);
|
|
|
|
// add the link to browse context and
|
|
// REVIEW: need to pass the proper friendly name
|
|
_phlbc->OnNavigateHlink(grfHLNF, pmkTarget, pszLocation, NULL, NULL);
|
|
}
|
|
|
|
put_Visible(TRUE);
|
|
|
|
SetForegroundWindow(hwndFrame);
|
|
}
|
|
|
|
//
|
|
// According to SriniK, we need to call IHlinkSite::OnNavigationComplete
|
|
// before returning from IHlinkFrame::Navigate with S_OK. (SatoNa)
|
|
//
|
|
if (pihlNavigate)
|
|
{
|
|
BOOL fExternal = FALSE;
|
|
if (_phlbc && _pbs)
|
|
{
|
|
ITravelLog* ptl;
|
|
if (SUCCEEDED(_pbs->GetTravelLog(&ptl)))
|
|
{
|
|
if (FAILED(ptl->GetTravelEntry(_pbs, 0, NULL)))
|
|
{
|
|
TraceMsg(DM_HLINKTRACE, "CIEFA::_NavMag this is external nav. Don't call OnNavigationComplete");
|
|
fExternal = TRUE;
|
|
}
|
|
else if (SUCCEEDED(ptl->GetTravelEntry(_pbs, TLOG_BACKEXTERNAL, NULL)))
|
|
{
|
|
TraceMsg(DM_HLINKTRACE, "CIEFA::_NavMag this is external for. Don't call OnNavigationComplete");
|
|
fExternal = TRUE;
|
|
}
|
|
ptl->Release();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Don't call OnNavigationComplete if this is an external navigation.
|
|
//
|
|
if (!fExternal)
|
|
{
|
|
IHlinkSite* pihlSite = NULL;
|
|
DWORD dwSiteData;
|
|
HRESULT hresT = pihlNavigate->GetHlinkSite(&pihlSite, &dwSiteData);
|
|
if (SUCCEEDED(hresT) && pihlSite)
|
|
{
|
|
TraceMsg(DM_HLINKTRACE, "CIEFA::_NavMag calling OnNavigationComplete");
|
|
hresT = pihlSite->OnNavigationComplete(dwSiteData, 0, S_OK, L"");
|
|
if (FAILED(hresT))
|
|
{
|
|
TraceMsg(DM_ERROR, "CIEFA::Navigat OnNavComplete failed %x", hresT);
|
|
}
|
|
pihlSite->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// HACK - what we really want is a good private marshalled interface - zekel 8-AUG-97
|
|
// to the Browser. but for now we will overload the NavigateHack method,
|
|
// because it is simple and quick for ship.
|
|
//
|
|
#define HLNF_REFERRERHACK 0x40000000
|
|
HRESULT CIEFrameAuto::_ReferrerHack(LPCWSTR pszUrl)
|
|
{
|
|
if (_pbs == NULL) //Make sure we have a IBrowserService.
|
|
return S_FALSE;
|
|
|
|
LPITEMIDLIST pidl;
|
|
|
|
if (SUCCEEDED(_pbs->IEParseDisplayName(CP_ACP, pszUrl, &pidl)))
|
|
{
|
|
ASSERT(pidl);
|
|
_pbs->SetReferrer(pidl);
|
|
ILFree(pidl);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CIEFrameAuto::NavigateHack(DWORD grfHLNF, IBindCtx *pbc, IBindStatusCallback *pibsc, LPCWSTR pszTargetName, LPCWSTR pszUrl, LPCWSTR pszLocation)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
IBindCtx * pBindCtx = pbc;
|
|
IUnknown * pNotify = NULL;
|
|
IUnknown * pBindCtxParam = NULL;
|
|
BOOL fAsyncCalled = FALSE;
|
|
|
|
// Check if we are actually a native frame build...
|
|
if (pbc)
|
|
{
|
|
hres = pbc->GetObjectParam(KEY_BINDCONTEXTPARAM, &pBindCtxParam);
|
|
}
|
|
|
|
if (SUCCEEDED(hres) && pBindCtxParam)
|
|
{
|
|
// NavigateHack can be called multiple times, and we only want to create the
|
|
// new bind context the first time. Since the ITargetNotify pointer is removed
|
|
// after the first use, we can check that to make sure.
|
|
// get and transfer the target notify pointer.
|
|
hres = pbc->GetObjectParam(TARGET_NOTIFY_OBJECT_NAME, &pNotify);
|
|
if (SUCCEEDED(hres) && pNotify)
|
|
{
|
|
// The call is coming from a native frame build of MSHTML.
|
|
// We can not use their bind context, create a new one and transfer
|
|
// parameters.
|
|
// The old bind context is going to be released by the creator, so do not
|
|
// make a release call on it.
|
|
hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, &pBindCtx, 0);
|
|
if(FAILED(hres))
|
|
goto Exit;
|
|
|
|
fAsyncCalled = TRUE;
|
|
|
|
// carry over the ITargetNotify2 pointer.
|
|
hres = pBindCtx->RegisterObjectParam( TARGET_NOTIFY_OBJECT_NAME, pNotify );
|
|
if (FAILED(hres))
|
|
goto Exit;
|
|
|
|
pNotify->Release();
|
|
pNotify = NULL;
|
|
|
|
// carry over the bind context parameter.
|
|
hres = pBindCtx->RegisterObjectParam( KEY_BINDCONTEXTPARAM, pBindCtxParam );
|
|
if (FAILED(hres))
|
|
goto Exit;
|
|
|
|
{
|
|
IUnknown * pDwnBindInfo = NULL;
|
|
|
|
if (SUCCEEDED(pbc->GetObjectParam(SZ_DWNBINDINFO_OBJECTPARAM, &pDwnBindInfo)) && pDwnBindInfo)
|
|
{
|
|
pBindCtx->RegisterObjectParam(SZ_DWNBINDINFO_OBJECTPARAM, pDwnBindInfo);
|
|
pDwnBindInfo->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
pBindCtxParam->Release();
|
|
pBindCtxParam = NULL;
|
|
}
|
|
|
|
if (IsFlagSet(grfHLNF, HLNF_REFERRERHACK))
|
|
hres = _ReferrerHack(pszUrl);
|
|
else
|
|
hres = _NavigateMagnum(grfHLNF, pBindCtx, pibsc, pszTargetName, pszUrl, pszLocation, NULL, NULL);
|
|
|
|
Exit:
|
|
SAFERELEASE(pNotify);
|
|
SAFERELEASE(pBindCtxParam);
|
|
|
|
// If the call failed anywhere, we can not be sure the new document
|
|
// will free the object parameter that is in the bind context
|
|
// we have created in this function.
|
|
if (FAILED(hres) && pBindCtx)
|
|
{
|
|
// we don't want to change the return code here.
|
|
pBindCtx->RevokeObjectParam(KEY_BINDCONTEXTPARAM);
|
|
pBindCtx->RevokeObjectParam(TARGET_NOTIFY_OBJECT_NAME);
|
|
}
|
|
|
|
if (fAsyncCalled)
|
|
pBindCtx->Release();
|
|
|
|
return hres;
|
|
}
|
|
|
|
// passing NULL pibsc and pbc will make be like "ReleaseNavigationState"
|
|
// passing -1 for pihlNavigate will cancel pending navigation
|
|
|
|
HRESULT CIEFrameAuto::Navigate(DWORD grfHLNF, IBindCtx *pbc,
|
|
IBindStatusCallback *pibsc, IHlink *pihlNavigate)
|
|
{
|
|
IMoniker* pmkTarget = NULL;
|
|
LPOLESTR pwszDisplayName = NULL;
|
|
LPOLESTR pwszLocation = NULL;
|
|
LPOLESTR pwszFrameName = NULL;
|
|
HRESULT hres = S_OK;
|
|
|
|
if (pihlNavigate && ((IHlink *)-1) != pihlNavigate)
|
|
{
|
|
pihlNavigate->GetTargetFrameName(&pwszFrameName);
|
|
|
|
//
|
|
// Note that we are discarding "relative" portion.
|
|
//
|
|
hres = pihlNavigate->GetMonikerReference(HLINKGETREF_ABSOLUTE, &pmkTarget, &pwszLocation);
|
|
|
|
HFRMMSG2("Navigate pihl->GetMonRef returned", hres, pmkTarget);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
IBindCtx* pbcLocal;
|
|
|
|
if (pbc)
|
|
{
|
|
pbcLocal = pbc;
|
|
pbcLocal->AddRef();
|
|
}
|
|
else
|
|
{
|
|
hres = CreateBindCtx(0, &pbcLocal);
|
|
}
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = pmkTarget->GetDisplayName(pbcLocal, NULL, &pwszDisplayName);
|
|
pbcLocal->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = _NavigateMagnum(grfHLNF, pbc, pibsc, pwszFrameName, pwszDisplayName, pwszLocation, pihlNavigate, pmkTarget);
|
|
}
|
|
if (pwszFrameName)
|
|
{
|
|
OleFree(pwszFrameName);
|
|
}
|
|
if (pwszDisplayName)
|
|
{
|
|
OleFree(pwszDisplayName);
|
|
}
|
|
if (pwszLocation)
|
|
{
|
|
OleFree(pwszLocation);
|
|
}
|
|
if (pmkTarget)
|
|
{
|
|
pmkTarget->Release();
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CIEFrameAuto::OnNavigate(DWORD grfHLNF,
|
|
/* [unique][in] */ IMoniker *pimkTarget,
|
|
/* [unique][in] */ LPCWSTR pwzLocation,
|
|
/* [unique][in] */ LPCWSTR pwzFriendlyName,
|
|
/* [in] */ DWORD dwreserved)
|
|
{
|
|
TraceMsg(0, "shlf TR ::OnNavigate called");
|
|
return S_OK;
|
|
}
|
|
|
|
void CIEFrameAuto::_CancelPendingNavigation(VARIANTARG* pvar)
|
|
{
|
|
TraceMsg(0, "shd TR _CancelPendingNavigation called");
|
|
if (_pmsc)
|
|
{
|
|
TraceMsg(0, "shd TR _CancelPendingNavigation calling _pmsc->Exec");
|
|
_pmsc->Exec(&CGID_Explorer, SBCMDID_CANCELNAVIGATION, 0, pvar, NULL);
|
|
}
|
|
}
|
|
|
|
// *** ITargetNotify ***
|
|
|
|
void
|
|
CIEFrameAuto::_HandleOpenOptions( IUnknown * pUnkDestination, ITargetNotify * ptgnNotify)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
ITargetNotify2 * ptgnNotify2 = NULL;
|
|
|
|
if (!pUnkDestination || !ptgnNotify)
|
|
return;
|
|
|
|
if (SUCCEEDED(ptgnNotify->QueryInterface( IID_ITargetNotify2, (void **)&ptgnNotify2)))
|
|
{
|
|
BSTR bstrOptions = NULL;
|
|
|
|
ASSERT(ptgnNotify2);
|
|
|
|
// Apply the options only if the initator of the navigation
|
|
// asks for it.
|
|
|
|
if (S_OK == ptgnNotify2->GetOptionString(&bstrOptions))
|
|
{
|
|
_omwin._OpenOptions.ReInitialize();
|
|
|
|
if (bstrOptions)
|
|
{
|
|
_omwin._ParseOptionString(bstrOptions, ptgnNotify2);
|
|
|
|
// We are done with the options string, release it
|
|
SysFreeString(bstrOptions);
|
|
}
|
|
|
|
// Apply the options now.
|
|
//
|
|
IWebBrowser2 * pNewIE;
|
|
|
|
if (SUCCEEDED(pUnkDestination->QueryInterface(IID_PPV_ARG(IWebBrowser2, &pNewIE))))
|
|
{
|
|
_omwin._ApplyOpenOptions(pNewIE);
|
|
pNewIE->Release();
|
|
}
|
|
}
|
|
|
|
ptgnNotify2->Release();
|
|
|
|
}
|
|
}
|
|
|
|
HRESULT CIEFrameAuto::OnCreate(IUnknown *pUnkDestination, ULONG cbCookie)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
|
|
if (cbCookie == (ULONG)_cbCookie && _ptgnNotify)
|
|
{
|
|
_HandleOpenOptions( pUnkDestination, _ptgnNotify);
|
|
|
|
hres = _ptgnNotify->OnCreate(pUnkDestination, cbCookie);
|
|
SAFERELEASE(_ptgnNotify);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CIEFrameAuto::OnReuse(IUnknown *pUnkDestination)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
#define NOTIFY_WAIT_TIMEOUT (60000)
|
|
// chrisfra 10/10/96: do we need EnableModeless(FALSE)/(TRUE) around
|
|
// our little loop, or is the busy flag (which is set) sufficient?
|
|
|
|
HRESULT CIEFrameAuto::_WaitForNotify()
|
|
{
|
|
if (_ptgnNotify && IsInternetExplorerApp())
|
|
{
|
|
DWORD dwObject, msWait, msStart = GetTickCount();
|
|
|
|
goto DOPEEK;
|
|
|
|
while (_ptgnNotify)
|
|
{
|
|
// NB We need to let the run dialog become active so we have to half handle sent
|
|
// messages but we don't want to handle any input events or we'll swallow the
|
|
// type-ahead.
|
|
msWait = GetTickCount();
|
|
if (msWait - msStart > NOTIFY_WAIT_TIMEOUT)
|
|
break;
|
|
|
|
msWait = NOTIFY_WAIT_TIMEOUT - (msWait - msStart);
|
|
dwObject = MsgWaitForMultipleObjects(0, NULL, FALSE, msWait, QS_ALLINPUT);
|
|
// Are we done waiting?
|
|
switch (dwObject)
|
|
{
|
|
case WAIT_FAILED:
|
|
break;
|
|
|
|
case WAIT_OBJECT_0:
|
|
DOPEEK:
|
|
// got a message, dispatch it and wait again
|
|
MSG msg;
|
|
while (PeekMessage(&msg, NULL,0, 0, PM_REMOVE))
|
|
{
|
|
DispatchMessage(&msg);
|
|
if (_ptgnNotify == NULL ||
|
|
((GetTickCount() - msStart) > NOTIFY_WAIT_TIMEOUT))
|
|
break;
|
|
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CIEFrameAuto::_RegisterCallback(TCHAR *szFrameName, ITargetNotify *ptgnNotify)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
SAFERELEASE(_ptgnNotify);
|
|
|
|
_fRegistered = 0;
|
|
|
|
if (ptgnNotify)
|
|
{
|
|
IDispatch *pid;
|
|
hr = QueryInterface(IID_PPV_ARG(IDispatch, &pid));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = E_FAIL;
|
|
IShellWindows *psw = WinList_GetShellWindows(TRUE);
|
|
if (psw != NULL)
|
|
{
|
|
long cbCookie;
|
|
hr = psw->Register(pid, NULL, SWC_CALLBACK, &cbCookie);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR szCookie[25]; // big enough for "_[cbCookie]"
|
|
int slenCookie;
|
|
int slenName;
|
|
int slenMin;
|
|
|
|
_cbCookie = cbCookie;
|
|
_fRegistered = 1;
|
|
_ptgnNotify = ptgnNotify;
|
|
_ptgnNotify->AddRef();
|
|
|
|
// prepend unique id to target -- tells created WebBrowserOC to
|
|
// register the remainder (if any) as frame name and to perform
|
|
// callbacks on all registered callbacks
|
|
wnsprintf(szCookie, ARRAYSIZE(szCookie), TEXT("_[%ld]"), cbCookie);
|
|
slenCookie = lstrlen(szCookie);
|
|
slenName = lstrlen(szFrameName);
|
|
slenMin = min((int)MAX_URL_STRING-slenCookie,slenName);
|
|
MoveMemory(&szFrameName[slenCookie], szFrameName, CbFromCch(slenMin));
|
|
szFrameName[slenCookie+slenMin] = 0;
|
|
CopyMemory(szFrameName, szCookie, CbFromCch(slenCookie));
|
|
}
|
|
psw->Release();
|
|
}
|
|
pid->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CIEFrameAuto::_RevokeCallback()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (_fRegistered)
|
|
{
|
|
IShellWindows *psw = WinList_GetShellWindows(TRUE);
|
|
if (psw != NULL)
|
|
{
|
|
hr = psw->Revoke(_cbCookie);
|
|
psw->Release();
|
|
}
|
|
}
|
|
SAFERELEASE(_ptgnNotify);
|
|
_fRegistered = 0;
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// HACK - what we really want is a good private marshalled interface - zekel 8-AUG-97
|
|
// to the Browser. but for now we will overload the NavigateHack method,
|
|
// because it is simple and quick for ship.
|
|
//
|
|
void CIEFrameAuto::_SetReferrer(ITargetFramePriv *ptgfp)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
WCHAR szUrl[MAX_URL_STRING];
|
|
|
|
ASSERT(ptgfp);
|
|
|
|
//Make sure we have a IBrowserService.
|
|
if (_psb && SUCCEEDED(_pbs->GetPidl(&pidl)))
|
|
{
|
|
if (SUCCEEDED(_pbs->IEGetDisplayName(pidl, szUrl, SHGDN_FORPARSING)))
|
|
ptgfp->NavigateHack(HLNF_REFERRERHACK, NULL, NULL, NULL, szUrl, NULL);
|
|
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
|
|
BOOL _ShouldInvokeDefaultBrowserOnNewWindow(IUnknown *punk)
|
|
{
|
|
BOOL fResult = FALSE;
|
|
|
|
IOleCommandTarget *poct;
|
|
|
|
if (SUCCEEDED(IUnknown_QueryService(punk, SID_STopLevelBrowser, IID_PPV_ARG(IOleCommandTarget, &poct))))
|
|
{
|
|
VARIANT var;
|
|
|
|
var.vt = VT_EMPTY;
|
|
|
|
if (SUCCEEDED(poct->Exec(&CGID_InternetExplorer,
|
|
IECMDID_GET_INVOKE_DEFAULT_BROWSER_ON_NEW_WINDOW,
|
|
0,
|
|
NULL,
|
|
&var)))
|
|
{
|
|
fResult = var.boolVal ? TRUE : FALSE;
|
|
}
|
|
|
|
poct->Release();
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
|
|
HRESULT CIEFrameAuto::_JumpTo(IBindCtx *pbc, LPWSTR pszLocation, DWORD grfHLNF, IBindStatusCallback *pibsc, IHlink *pihlNavigate, LPCWSTR pszFrameName, LPCWSTR pszUrl)
|
|
{
|
|
LPITEMIDLIST pidl = NULL;
|
|
HRESULT hres;
|
|
ITargetNotify *ptgnNotify = NULL;
|
|
IUnknown *punkNotify = NULL;
|
|
IUnknown *punkThis = NULL;
|
|
UINT uiCP = CP_ACP;
|
|
|
|
// Get the current document codepage from Trident and use it for url string conversion if necessary.
|
|
if (!(grfHLNF & HLNF_ALLOW_AUTONAVIGATE) && _pmsc)
|
|
{
|
|
VARIANT varOut = { 0 };
|
|
VARIANT varIn = { 0 };
|
|
|
|
varIn.vt = VT_I4;
|
|
varIn.lVal = DFC_URLCHARSET; // we want the doc's url charset
|
|
|
|
if (SUCCEEDED(_pmsc->Exec(&CGID_ShellDocView, SHDVID_DOCFAMILYCHARSET, 0, &varIn, &varOut)))
|
|
uiCP = (UINT)varOut.lVal;
|
|
}
|
|
|
|
// Note that we are simply passing the pidl to ISB::BrowseObject,
|
|
// assuming that new shell32.dll allows us to bind to DocObject
|
|
// documents.
|
|
//
|
|
|
|
DWORD flags = (grfHLNF & HLNF_OPENINNEWWINDOW) ?
|
|
(SBSP_NEWBROWSER | SBSP_ABSOLUTE | SBSP_INITIATEDBYHLINKFRAME) :
|
|
(SBSP_SAMEBROWSER | SBSP_ABSOLUTE | SBSP_INITIATEDBYHLINKFRAME);
|
|
|
|
|
|
flags |= ((grfHLNF & HLNF_ALLOW_AUTONAVIGATE) ? (SBSP_ALLOW_AUTONAVIGATE) : 0);
|
|
flags |= ((grfHLNF & SHHLNF_WRITENOHISTORY) ? (SBSP_WRITENOHISTORY) : 0);
|
|
flags |= ((grfHLNF & SHHLNF_NOAUTOSELECT) ? (SBSP_NOAUTOSELECT) : 0);
|
|
|
|
if (pbc && SUCCEEDED(pbc->GetObjectParam(TARGET_NOTIFY_OBJECT_NAME, &punkNotify)))
|
|
{
|
|
if (FAILED(punkNotify->QueryInterface(IID_PPV_ARG(ITargetNotify, &ptgnNotify))))
|
|
ptgnNotify = NULL;
|
|
|
|
punkNotify->Release();
|
|
QueryInterface(IID_PPV_ARG(IUnknown, &punkThis));
|
|
}
|
|
|
|
if (grfHLNF & HLNF_CREATENOHISTORY)
|
|
flags |= SBSP_REDIRECT;
|
|
|
|
if (flags & SBSP_NEWBROWSER)
|
|
{
|
|
TCHAR *pszHeaders = NULL;
|
|
BYTE *pPostData = NULL;
|
|
DWORD cbPostData = 0;
|
|
TCHAR szFrameName[MAX_URL_STRING+1];
|
|
STGMEDIUM stgPostData = { TYMED_NULL, NULL, NULL };
|
|
|
|
//Qfe:1478 If restricted to open in new window, return failure.
|
|
if ((grfHLNF & HLNF_OPENINNEWWINDOW)
|
|
&& SHIsRestricted2W(_hwnd, REST_NoOpeninNewWnd, NULL, 0))
|
|
{
|
|
SAFERELEASE(punkThis);
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
if ((_ShouldInvokeDefaultBrowserOnNewWindow(_psb) || IsDesktopFrame(_psb)) && !ShouldNavigateInIE(pszUrl))
|
|
{
|
|
// IE is not the default browser so we'll ShellExecute the Url since someone
|
|
// has told us that's the behaviour they prefer.
|
|
HINSTANCE hinstRet = ShellExecuteW(NULL, NULL, pszUrl, NULL, NULL, SW_SHOWNORMAL);
|
|
|
|
hres = ((UINT_PTR)hinstRet) <= 32 ? E_FAIL : S_OK;
|
|
}
|
|
else
|
|
{
|
|
|
|
szFrameName[0] = 0;
|
|
|
|
// Here is where if we are doing a new window we must
|
|
// extract frame, post etc and append to pidl. These must
|
|
// be done in the following order (to match extraction code):
|
|
// URLID_FRAMENAME,URLID_POSTDATA,URLID_HEADERS
|
|
|
|
if (pszFrameName)
|
|
{
|
|
SHUnicodeToTChar(pszFrameName, szFrameName, ARRAYSIZE(szFrameName));
|
|
}
|
|
|
|
|
|
if (pibsc)
|
|
{
|
|
GetHeadersAndPostData(pibsc,&pszHeaders,&stgPostData,&cbPostData, NULL);
|
|
|
|
if (stgPostData.tymed == TYMED_HGLOBAL)
|
|
{
|
|
pPostData = (LPBYTE) stgPostData.hGlobal;
|
|
}
|
|
}
|
|
|
|
hres = _PidlFromUrlEtc(uiCP, pszUrl, pszLocation, &pidl);
|
|
|
|
HFRMMSG2("_JumpTo _PidlFromUrlEtc returned", hres, pidl);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
IUnknown* punkNewWindow = NULL;
|
|
BOOL fCancel = FALSE;
|
|
|
|
// The NewWindow2 event may return the window for us.
|
|
FireEvent_NewWindow2(_GetOuter(), &punkNewWindow, &fCancel);
|
|
if (!fCancel)
|
|
{
|
|
BOOL fProcessed = FALSE;
|
|
|
|
// We might need the old NewWindow event...
|
|
if (!punkNewWindow)
|
|
{
|
|
_RegisterCallback(szFrameName, ptgnNotify);
|
|
|
|
// fire an event to indicate a new window needs to be created
|
|
// to allow a container to handle it itself if it wants
|
|
// since we may be aggregated, QI our parent
|
|
|
|
// Yet another Compuserve workaround (IE 60688):
|
|
// If the target frame name is "_blank", Compuserve will pass that name
|
|
// in to the Navigate call of the new window. We would then create a new window
|
|
// (which would fire this event) causing a loop. Break the recursion by sending
|
|
// an empty string for the frame name.
|
|
HWND hwnd = _GetHWND();
|
|
|
|
if (hwnd)
|
|
{
|
|
FireEvent_NewWindow(_GetOuter(), hwnd, pidl,pszLocation,0,
|
|
StrCmpI(szFrameName, TEXT("_blank")) ? szFrameName : TEXT(""), // Target frame name
|
|
pPostData,cbPostData,pszHeaders,&fProcessed);
|
|
}
|
|
}
|
|
|
|
if (!fProcessed)
|
|
{
|
|
if (!punkNewWindow)
|
|
{
|
|
#ifdef INCLUDE_BUSTED_OC_QI
|
|
IUnknown* pdvb = NULL;
|
|
#endif
|
|
_RevokeCallback();
|
|
|
|
#ifdef INCLUDE_BUSTED_OC_QI
|
|
// For some unidentifiable reason the old code did NOT
|
|
// create a new window if we were hosted in the WebBrowserOC.
|
|
// mikesh/cheechew/jeremys/chrisfra don't know why this happens.
|
|
// Who knows what app will break if we change this...
|
|
// (Note: IDefViewBrowser is a CWebBrowseSB only interface)
|
|
//
|
|
// NOTE: chrisfra 3/11/97, this code breaks open a
|
|
// new window for a non-existent target, when in
|
|
// desktop component or browser band
|
|
fCancel = !(_psbTop && FAILED(_psbTop->QueryInterface(IID_PPV_ARG(IDefViewBrowser, &pdvb))));
|
|
if (pdvb)
|
|
pdvb->Release();
|
|
#endif
|
|
}
|
|
|
|
// what we really want to do is just hand this off to
|
|
// _psbTop->BrowseObject and let it (CWebBrowserSB or CShellBrowser)
|
|
// decide whether to use HlinkFrameNavigate or not, but if we
|
|
// do that, then we lose the grfHLNF and pihlNavigate.
|
|
// So put that logic here...
|
|
//
|
|
if (!fCancel)
|
|
{
|
|
hres = CreateTargetFrame(pszFrameName, &punkNewWindow);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
// Notify ptgnNotify, then release and remove from bindctx
|
|
if (ptgnNotify)
|
|
{
|
|
_HandleOpenOptions( punkNewWindow, ptgnNotify);
|
|
|
|
ptgnNotify->OnCreate(punkNewWindow, GetTickCount());
|
|
|
|
ptgnNotify->Release();
|
|
ptgnNotify = NULL;
|
|
|
|
pbc->RevokeObjectParam(TARGET_NOTIFY_OBJECT_NAME);
|
|
}
|
|
|
|
LPHLINKFRAME phf;
|
|
|
|
hres = punkNewWindow->QueryInterface(IID_PPV_ARG(IHlinkFrame, &phf));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
ITargetFramePriv * ptgfp;
|
|
|
|
if (NULL == pihlNavigate)
|
|
{
|
|
hres = punkNewWindow->QueryInterface(IID_PPV_ARG(ITargetFramePriv, &ptgfp));
|
|
}
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if (pihlNavigate)
|
|
{
|
|
hres = phf->Navigate(grfHLNF & ~HLNF_OPENINNEWWINDOW,
|
|
pbc,
|
|
pibsc,
|
|
pihlNavigate);
|
|
}
|
|
else
|
|
{
|
|
// HACK - see this methods comments
|
|
_SetReferrer(ptgfp);
|
|
|
|
hres = ptgfp->NavigateHack(grfHLNF & ~HLNF_OPENINNEWWINDOW,
|
|
pbc,
|
|
pibsc,
|
|
NULL,
|
|
pszUrl,
|
|
pszLocation);
|
|
}
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
TraceMsg(DM_ERROR, "CIEFA::_JumpTo marshalled IHlinkFrame::Navigate failed %x", hres);
|
|
}
|
|
|
|
ShowHlinkFrameWindow(punkNewWindow);
|
|
if (NULL == pihlNavigate)
|
|
{
|
|
ptgfp->Release();
|
|
}
|
|
|
|
if(SUCCEEDED(hres) && pibsc)
|
|
{
|
|
_SetPendingNavigateContext(NULL, NULL);
|
|
}
|
|
|
|
}
|
|
phf->Release();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If NEWBROWSER is specified when there is no top level
|
|
// browser, we should ask IE/Shell to do browsing.
|
|
// We don't pass HLNF_OPENINNEWWINDOW in this case.
|
|
//
|
|
|
|
// Notify object doing navigation that we are the object implementing IWebBrowserApp
|
|
if (ptgnNotify) ptgnNotify->OnReuse(punkThis);
|
|
|
|
if (pihlNavigate)
|
|
{
|
|
hres = HlinkFrameNavigate(grfHLNF & ~HLNF_OPENINNEWWINDOW,
|
|
NULL, NULL, pihlNavigate, NULL);
|
|
}
|
|
else
|
|
{
|
|
hres = HlinkFrameNavigateNHL(grfHLNF & ~HLNF_OPENINNEWWINDOW,
|
|
NULL, NULL, NULL, pszUrl, pszLocation);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Oldstyle AOL or other 3rd Party, wait for registration of
|
|
// WebBrowserOC, which calls us back on _ptgnNotify
|
|
_WaitForNotify();
|
|
// We timed out the window create, notify caller
|
|
if (_ptgnNotify)
|
|
_ptgnNotify->OnCreate(NULL, 0);
|
|
_RevokeCallback();
|
|
}
|
|
}
|
|
|
|
if (punkNewWindow)
|
|
punkNewWindow->Release();
|
|
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(DM_ERROR, "IEAuto::_JumpTo _PidlFromUrlEtc (1) failed %x", hres);
|
|
}
|
|
}
|
|
if (pszHeaders)
|
|
{
|
|
LocalFree(pszHeaders);
|
|
pszHeaders = NULL;
|
|
}
|
|
|
|
if (stgPostData.tymed != TYMED_NULL)
|
|
{
|
|
ReleaseStgMedium(&stgPostData);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Notify object doing navigation that we are the object implementing IWebBrowserApp
|
|
if (ptgnNotify) ptgnNotify->OnReuse(punkThis);
|
|
|
|
hres = _PidlFromUrlEtc(uiCP, pszUrl, pszLocation, &pidl);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = _psb->BrowseObject(pidl, flags);
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(DM_ERROR, "IEAuto::_JumpTo _PidlFromUrlEtc (2) failed %x", hres);
|
|
}
|
|
}
|
|
|
|
if (pidl)
|
|
{
|
|
HFRMMSG2("_JumpTo _psb->BrowseObject returned", hres, 0);
|
|
ILFree(pidl);
|
|
}
|
|
|
|
if (ptgnNotify)
|
|
{
|
|
ptgnNotify->Release();
|
|
pbc->RevokeObjectParam(TARGET_NOTIFY_OBJECT_NAME);
|
|
}
|
|
|
|
SAFERELEASE(punkThis);
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
HRESULT CIEFrameAuto::QueryService(REFGUID guidService, REFIID riid, void ** ppvObj)
|
|
{
|
|
*ppvObj = NULL;
|
|
|
|
// WARNING: Note that we are not following the strict semantics of
|
|
// ISP::QueryService. It is, however, OK because this (the fact that
|
|
// IHlinkFrame support IServiceProvider) is not public.
|
|
|
|
if (IsEqualIID(guidService, SID_SOmWindow))
|
|
{
|
|
return _omwin.QueryInterface(riid, ppvObj);
|
|
}
|
|
else if (IsEqualIID(guidService, IID_IHlinkFrame))
|
|
{
|
|
SERVMSG("QueryService called", _pbc, _pbsc);
|
|
|
|
if (IsEqualIID(riid, IID_IBindCtx) && _pbc)
|
|
{
|
|
*ppvObj = _pbc;
|
|
_pbc->AddRef();
|
|
}
|
|
else if (IsEqualIID(riid, IID_IBindStatusCallback) && _pbsc)
|
|
{
|
|
*ppvObj = _pbsc;
|
|
_pbsc->AddRef();
|
|
}
|
|
else
|
|
{
|
|
return QueryInterface(riid, ppvObj);
|
|
}
|
|
}
|
|
else if (IsEqualIID(guidService, SID_PendingBindStatusCallback))
|
|
{
|
|
if (IsEqualIID(riid, IID_IBindStatusCallback) && _pbscPending)
|
|
{
|
|
*ppvObj = _pbscPending;
|
|
_pbscPending->AddRef();
|
|
}
|
|
}
|
|
else if (_psp)
|
|
{
|
|
return _psp->QueryService(guidService, riid, ppvObj);
|
|
}
|
|
|
|
return *ppvObj ? S_OK : E_FAIL;
|
|
}
|
|
|
|
|
|
HRESULT CIEFrameAuto::Exec(
|
|
/* [unique][in] */ const GUID *pguidCmdGroup,
|
|
/* [in] */ DWORD nCmdID,
|
|
/* [in] */ DWORD nCmdexecopt,
|
|
/* [unique][in] */ VARIANTARG *pvarargIn,
|
|
/* [unique][out][in] */ VARIANTARG *pvarargOut)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
|
|
if (pguidCmdGroup)
|
|
{
|
|
if (IsEqualGUID(CGID_Explorer, *pguidCmdGroup))
|
|
{
|
|
switch(nCmdID)
|
|
{
|
|
case SBCMDID_CANCELNAVIGATION:
|
|
_CancelPendingNavigation(NULL);
|
|
break;
|
|
|
|
case SBCMDID_SELECTHISTPIDL:
|
|
case SBCMDID_HISTSFOLDER:
|
|
if (_poctFrameTop)
|
|
hres = _poctFrameTop->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
else
|
|
hres = S_OK;
|
|
break;
|
|
|
|
case SBCMDID_IESHORTCUT:
|
|
#ifdef BROWSENEWPROCESS_STRICT // "Nav in new process" has become "Launch in new process", so this is no longer needed
|
|
// If this is an IE shortcut and browse in a new process is turned on
|
|
// and we are explorer.exe - we should pass on the request to navigate to
|
|
// this shortcut. The caller is expected to create a new window/process to
|
|
// launch this shortcut
|
|
if (IsBrowseNewProcessAndExplorer())
|
|
hres = E_FAIL;
|
|
else
|
|
#endif
|
|
hres = _NavIEShortcut(pvarargIn,pvarargOut);
|
|
|
|
break;
|
|
|
|
case SBCMDID_GETSHORTCUTPATH:
|
|
if (_pwszShortcutPath && pvarargOut)
|
|
{
|
|
pvarargOut->bstrVal = SysAllocString(_pwszShortcutPath);
|
|
if (pvarargOut->bstrVal)
|
|
pvarargOut->vt = VT_BSTR; //no need to set hres=S_OK since it is inited already
|
|
else
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
if (pvarargOut)
|
|
pvarargOut->vt = VT_EMPTY;
|
|
|
|
hres = E_FAIL;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
hres = OLECMDERR_E_NOTSUPPORTED;
|
|
}
|
|
}
|
|
else if (IsEqualGUID(CGID_ShortCut, *pguidCmdGroup))
|
|
{
|
|
if (_poctFrameTop) // we must check!
|
|
hres = _poctFrameTop->Exec(&CGID_ShortCut, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
else
|
|
hres = OLECMDERR_E_NOTSUPPORTED;
|
|
}
|
|
else if (IsEqualGUID(CGID_ShellDocView, *pguidCmdGroup))
|
|
{
|
|
switch (nCmdID)
|
|
{
|
|
case SHDVID_DELEGATEWINDOWOM:
|
|
_omwin.SetDelegationPolicy(V_BOOL(pvarargIn));
|
|
break;
|
|
default:
|
|
hres = OLECMDERR_E_NOTSUPPORTED;
|
|
}
|
|
}
|
|
else if (IsEqualGUID(CGID_InternetExplorer, *pguidCmdGroup))
|
|
// CGID_InternetExplorer are public defined in msiehost.h
|
|
{
|
|
switch (nCmdID)
|
|
{
|
|
case IECMDID_CLEAR_AUTOCOMPLETE_FOR_FORMS:
|
|
{
|
|
if (pvarargIn->vt == VT_I4)
|
|
{
|
|
hres = ClearAutoSuggestForForms(V_I4(pvarargIn));
|
|
}
|
|
else
|
|
hres = E_INVALIDARG;
|
|
}
|
|
break;
|
|
|
|
case IECMDID_SETID_AUTOCOMPLETE_FOR_FORMS:
|
|
{
|
|
if ((pvarargIn->vt == VT_UI8) ||
|
|
(pvarargIn->vt == VT_I8))
|
|
{
|
|
hres = SetIdAutoSuggestForForms(((GUID *)(&pvarargIn->ullVal)), _omwin.IntelliForms());
|
|
}
|
|
else
|
|
hres = E_INVALIDARG;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
hres = OLECMDERR_E_NOTSUPPORTED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = OLECMDERR_E_UNKNOWNGROUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = OLECMDERR_E_UNKNOWNGROUP;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
BOOL CIEFrameAuto::_fNavigationPending()
|
|
{
|
|
// unfortunately, the hyperlink frame doesn't REALLY know when there's
|
|
// a navigation pending or not because people might not call OnReleaseNavigation.
|
|
// only the real browser knows.
|
|
|
|
if (_pmsc)
|
|
{
|
|
MSOCMD rgCmd;
|
|
rgCmd.cmdID = SBCMDID_CANCELNAVIGATION;
|
|
rgCmd.cmdf = 0;
|
|
|
|
_pmsc->QueryStatus(&CGID_Explorer, 1, &rgCmd, NULL);
|
|
return (rgCmd.cmdf & MSOCMDF_ENABLED);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT CIEFrameAuto::QueryStatus(const GUID *pguidCmdGroup,
|
|
ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
|
|
{
|
|
if (pguidCmdGroup && IsEqualGUID(CGID_Explorer, *pguidCmdGroup))
|
|
{
|
|
for (ULONG i = 0; i < cCmds; i++)
|
|
{
|
|
switch (rgCmds[i].cmdID)
|
|
{
|
|
case SBCMDID_CANCELNAVIGATION:
|
|
rgCmds[i].cmdf = _fNavigationPending() ? MSOCMDF_ENABLED : 0;
|
|
break;
|
|
|
|
case SBCMDID_WRITEHIST:
|
|
rgCmds[i].cmdf = _fSuppressHistory ? 0:MSOCMDF_ENABLED;
|
|
break;
|
|
|
|
case SBCMDID_SELECTHISTPIDL:
|
|
rgCmds[i].cmdf = _fSuppressSelect || !_poctFrameTop ? 0:MSOCMDF_ENABLED;
|
|
break;
|
|
|
|
default:
|
|
rgCmds[i].cmdf = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return OLECMDERR_E_UNKNOWNGROUP;
|
|
}
|
|
|
|
if (pcmdtext)
|
|
{
|
|
pcmdtext->cmdtextf = MSOCMDTEXTF_NONE;
|
|
pcmdtext->cwActual = 0;
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT CIEFrameAuto::_PidlFromUrlEtc(UINT uiCP, LPCWSTR pszUrl, LPWSTR pszLocation, LPITEMIDLIST* ppidl)
|
|
{
|
|
*ppidl = NULL; // assumes error
|
|
|
|
// ALGORITHM:
|
|
// - First, we call IEParseDisplayName to generate the pidl
|
|
// to the specified URL or file name.
|
|
// - if we have fragment (pszLocation) specified,
|
|
// we call IEILAppendFragment() to add the hidden fragment id
|
|
if (_pbs == NULL) //Make sure we have a IBrowserService.
|
|
return (S_FALSE);
|
|
|
|
HRESULT hr = _pbs->IEParseDisplayName(uiCP, pszUrl, ppidl);
|
|
|
|
// This is ugly, if it's a file path that failed to parse because
|
|
// it doesn't exist, we want to create a SimpleIDList so we display
|
|
// a res: navigation failed IFrame instead of the err dlg displayed
|
|
// in DisplayParseError() below.
|
|
if (FAILED(hr))
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
DWORD cchBuf = ARRAYSIZE(szPath);
|
|
|
|
// If it's a FILE URL, convert it to a path.
|
|
if (IsFileUrlW(pszUrl) && SUCCEEDED(PathCreateFromUrl(pszUrl, szPath, &cchBuf, 0)))
|
|
{
|
|
// That worked, we are done because our buffer is now full.
|
|
}
|
|
else
|
|
{
|
|
// We now need to copy to the buffer and we assume it's a path.
|
|
StrCpyN(szPath, pszUrl, ARRAYSIZE(szPath));
|
|
}
|
|
|
|
*ppidl = SHSimpleIDListFromPath(szPath);
|
|
if (*ppidl)
|
|
hr = S_OK;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (pszLocation && *pszLocation)
|
|
{
|
|
*ppidl = IEILAppendFragment(*ppidl, pszLocation);
|
|
hr = *ppidl ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// NOTES: This behavior is new in IE4.0. We are adding
|
|
// this message box based on the request (bug-report)
|
|
// from Office guys. (SatoNa)
|
|
//
|
|
hr = _pbs->DisplayParseError(hr, pszUrl);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CIEFrameAuto::_NavIEShortcut(VARIANT *pvarIn, VARIANT *pvarargOut)
|
|
{
|
|
// need to validate verb and clsid
|
|
HRESULT hr = E_ACCESSDENIED;
|
|
READYSTATE ready;
|
|
BOOL fForceNavigate = pvarargOut ? ((VT_BOOL == pvarargOut->vt ) && (pvarargOut->boolVal)) : FALSE;
|
|
|
|
get_ReadyState(&ready);
|
|
|
|
ASSERT(pvarIn);
|
|
ASSERT(pvarIn->vt == VT_BSTR);
|
|
//
|
|
// we dont want to allow the exec to go through if this window
|
|
// is busy with something else. we should probably allow
|
|
// READYSTATE_COMPLETE and READYSTATE_UNINITIALIZED.
|
|
// if we use READYSTATE_UNINITIALIZED, we need to init the browser
|
|
// and make it visible and stuff like that. something to the
|
|
// check that IPersisteHistory->LoadHistory() does in shvocx.cpp.
|
|
// right now we will only allow COMPLETE.
|
|
//
|
|
TraceMsgW(DM_SHELLEXECOBJECT, "[%X] IEAuto_NavIEShortcut entered '%s' ready = %d", this, pvarIn->bstrVal, ready);
|
|
|
|
|
|
if (((ready == READYSTATE_COMPLETE || ready == READYSTATE_UNINITIALIZED) || (fForceNavigate))
|
|
&& S_OK == IUnknown_Exec(_psbTop, &CGID_Explorer, SBCMDID_ISIEMODEBROWSER, 0, NULL, NULL))
|
|
|
|
{
|
|
IPersistFile *ppf;
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_ALL, IID_PPV_ARG(IPersistFile, &ppf))))
|
|
{
|
|
if (SUCCEEDED(ppf->Load(pvarIn->bstrVal, STGM_READ)))
|
|
{
|
|
LPWSTR pszUrl = NULL;
|
|
TraceMsg(DM_SHELLEXECOBJECT, "[%X] IEAuto_NavIEShortcut shortcut inited with file", this);
|
|
|
|
IUniformResourceLocatorW *purl;
|
|
if (SUCCEEDED(ppf->QueryInterface(IID_PPV_ARG(IUniformResourceLocatorW, &purl))))
|
|
{
|
|
purl->GetURL(&pszUrl);
|
|
purl->Release();
|
|
}
|
|
|
|
if (pszUrl)
|
|
{
|
|
TraceMsgW(DM_SHELLEXECOBJECT, "[%X] IEAuto_NavIEShortcut found %s", this, pszUrl);
|
|
|
|
LPITEMIDLIST pidl;
|
|
IEParseDisplayNameW(CP_ACP, pszUrl, &pidl);
|
|
if (pidl)
|
|
{
|
|
ASSERT(NULL == _pwszShortcutPathPending);
|
|
if (_pwszShortcutPathPending)
|
|
LocalFree(_pwszShortcutPathPending);
|
|
|
|
_pwszShortcutPathPending = StrDupW(pvarIn->bstrVal);
|
|
|
|
hr = _BrowseObject(pidl, SBSP_SAMEBROWSER);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (ready == READYSTATE_UNINITIALIZED)
|
|
put_Visible(VARIANT_TRUE);
|
|
HWND hwnd = _GetHWND();
|
|
if (hwnd)
|
|
{
|
|
if (IsIconic(hwnd))
|
|
ShowWindow(hwnd, SW_RESTORE);
|
|
else
|
|
SetForegroundWindow(hwnd);
|
|
}
|
|
}
|
|
ILFree(pidl);
|
|
}
|
|
SHFree(pszUrl);
|
|
}
|
|
}
|
|
ppf->Release();
|
|
}
|
|
}
|
|
TraceMsg(DM_SHELLEXECOBJECT, "IEAuto_NavIEShortcut returns 0x%X", hr);
|
|
|
|
return hr;
|
|
}
|
|
|