3942 lines
121 KiB
C++
3942 lines
121 KiB
C++
#include "priv.h"
|
|
|
|
#include "sccls.h"
|
|
#include "comcat.h"
|
|
#include <hliface.h>
|
|
#include "shlguid.h"
|
|
#include "shvocx.h"
|
|
#include "winlist.h"
|
|
#include <mshtml.h>
|
|
#include "stdenum.h"
|
|
#include "iface.h"
|
|
#include "resource.h"
|
|
#include "msiehost.h"
|
|
|
|
#include <mluisupp.h>
|
|
|
|
#define SUPERCLASS CShellOcx
|
|
|
|
#define MIN_HEIGHT 80 // minimum height of a ShellFolderViewOC
|
|
#define MIN_WIDTH 80 // minimum width of a ShellFolderViewOC.
|
|
#define DEF_WIDTH 300 // default width when we cannot get sizing information
|
|
#define DEF_HEIGHT 150 // default height when we cannot get sizing information
|
|
|
|
#define IPSMSG(psz) TraceMsg(TF_SHDCONTROL, "shv IPS::%s called", (psz))
|
|
#define IPSMSG2(psz, hres) TraceMsg(TF_SHDCONTROL, "shv IPS::%s %x", (psz), hres)
|
|
#define IPSMSG3(psz, hres, x, y) TraceMsg(TF_SHDCONTROL,"shv IPS::%s %x %d (%d)", (psz), hres, x, y)
|
|
#define IOOMSG(psz) TraceMsg(TF_SHDCONTROL, "shv IOO::%s called", (psz))
|
|
#define IOOMSG2(psz, i) TraceMsg(TF_SHDCONTROL, "shv IOO::%s called with (%d)", (psz), i)
|
|
#define IOOMSG3(psz, i, j) TraceMsg(TF_SHDCONTROL, "shv IOO::%s called with (%d, %d)", (psz), i, j)
|
|
#define IVOMSG(psz) TraceMsg(TF_SHDCONTROL, "shv IVO::%s called", (psz))
|
|
#define IVOMSG2(psz, i) TraceMsg(TF_SHDCONTROL, "shv IVO::%s called with (%d)", (psz), i)
|
|
#define IVOMSG3(psz, i, j) TraceMsg(TF_SHDCONTROL, "shv IVO::%s called with (%d, %d)", (psz), i, j)
|
|
#define PROPMSG(psz) TraceMsg(TF_SHDCONTROL, "shv %s", (psz))
|
|
#define PROPMSG2(psz, pstr) TraceMsg(TF_SHDCONTROL, "shv %s with [%s]", (psz), pstr)
|
|
#define PROPMSG3(psz, hex) TraceMsg(TF_SHDCONTROL, "shv %s with 0x%x", (psz), hex)
|
|
#define PRIVMSG(psz) TraceMsg(TF_SHDCONTROL, "shv %s", (psz))
|
|
#define CVOCBMSG(psz) TraceMsg(TF_SHDCONTROL, "shv CWebBrowserSB::%s", (psz))
|
|
#define IOIPAMSG(psz) TraceMsg(TF_SHDCONTROL, "shv IOIPA::%s", (psz));
|
|
|
|
#define ABS(i) (((i) < 0) ? -(i) : (i))
|
|
|
|
#define BOOL_TO_VARIANTBOOL(b) ((b) ? VARIANT_TRUE : VARIANT_FALSE)
|
|
#define VARIANTBOOL_TO_BOOL(vb) ((vb == VARIANT_FALSE) ? FALSE : TRUE)
|
|
|
|
// sizing messages are annoying, but occasionally useful:
|
|
#define DM_FORSEARCHBAND 0
|
|
|
|
static const OLEVERB c_averbsSV[] = {
|
|
{ 0, (LPWSTR)MAKEINTRESOURCE(IDS_VERB_EDIT), 0, OLEVERBATTRIB_ONCONTAINERMENU },
|
|
{ 0, NULL, 0, 0 }
|
|
};
|
|
static const OLEVERB c_averbsDesignSV[] = {
|
|
{ 0, NULL, 0, 0 }
|
|
};
|
|
|
|
#define HMODULE_NOTLOADED ((HMODULE)-1)
|
|
|
|
HRESULT TargetQueryService(IUnknown *punk, REFIID riid, void **ppvObj);
|
|
|
|
/*
|
|
* CMsgFilter - implementation of IMessageFilter
|
|
*
|
|
* Used to reject RPC-reentrant calls while inside AOL
|
|
*
|
|
*/
|
|
class CMsgFilter : public IMessageFilter {
|
|
public:
|
|
// *** IUnknown methods ***
|
|
STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj)
|
|
{
|
|
// This interface doesn't get QI'ed.
|
|
ASSERT(FALSE);
|
|
return E_NOINTERFACE;
|
|
};
|
|
virtual ULONG __stdcall AddRef(void) { return ++_cRef; };
|
|
virtual ULONG __stdcall Release(void) { ASSERT(_cRef > 0);
|
|
_cRef--;
|
|
if (_cRef > 0)
|
|
return _cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
};
|
|
|
|
// *** IMessageFilter specific methods ***
|
|
virtual DWORD __stdcall HandleInComingCall(
|
|
IN DWORD dwCallType,
|
|
IN HTASK htaskCaller,
|
|
IN DWORD dwTickCount,
|
|
IN LPINTERFACEINFO lpInterfaceInfo)
|
|
{
|
|
#ifdef DEBUG
|
|
WCHAR wszIID[39];
|
|
|
|
StringFromGUID2( lpInterfaceInfo->iid, wszIID, ARRAYSIZE(wszIID) );
|
|
|
|
TraceMsg(TF_SHDCONTROL, "shvMF HandleIncomingCall: calltype=%lx, pUnk=%lx, IID=%ws, wMethod=%hu",
|
|
dwCallType,
|
|
lpInterfaceInfo->pUnk,
|
|
wszIID,
|
|
lpInterfaceInfo->wMethod);
|
|
#endif
|
|
|
|
//
|
|
// The following statement guards against RPC-reentrancy by checking if
|
|
// the calltype is TOPLEVEL_CALLPENDING, which means that a call has arrived with a new
|
|
// logical threadid and that the object is currently waiting for a reply from a previous
|
|
// outgoing call. It's this type of call that has proven troublesome in the past with AOL.
|
|
//
|
|
// 2-Dec-97: AOL QFE: We need to allow resizing requests to pass through the message filter.
|
|
// These appear as IOleObject::SetExtent. Check the IID for IOleObject, and the
|
|
// wMethod for 17 (SetExtent is the 17th method in the vtable, Zero-based).
|
|
//
|
|
const int SetExtent = 17;
|
|
|
|
if ( ( dwCallType == CALLTYPE_TOPLEVEL_CALLPENDING )
|
|
&& !(IsEqualIID(lpInterfaceInfo->iid, IID_IOleObject) && lpInterfaceInfo->wMethod == SetExtent) )
|
|
{
|
|
#ifdef DEBUG
|
|
TraceMsg(TF_SHDCONTROL, "shvMF rejected call: calltype=%lx, pUnk=%lx, IID=%ws, wMethod=%hu",
|
|
dwCallType,
|
|
lpInterfaceInfo->pUnk,
|
|
wszIID,
|
|
lpInterfaceInfo->wMethod);
|
|
#endif
|
|
return SERVERCALL_RETRYLATER;
|
|
}
|
|
|
|
if (_lpMFOld)
|
|
{
|
|
HRESULT hr = _lpMFOld->HandleInComingCall(dwCallType, htaskCaller, dwTickCount, lpInterfaceInfo);
|
|
TraceMsg(TF_SHDCONTROL, "shvMF HIC Previous MF returned %x", hr);
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "shvMF HIC returning SERVERCALL_ISHANDLED.");
|
|
return SERVERCALL_ISHANDLED;
|
|
}
|
|
};
|
|
|
|
virtual DWORD __stdcall RetryRejectedCall(
|
|
IN HTASK htaskCallee,
|
|
IN DWORD dwTickCount,
|
|
IN DWORD dwRejectType)
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "shv MF RetryRejectedCall htaskCallee=%x, dwTickCount=%x, dwRejectType=%x",
|
|
htaskCallee,
|
|
dwTickCount,
|
|
dwRejectType);
|
|
|
|
if (_lpMFOld)
|
|
{
|
|
HRESULT hr = _lpMFOld->RetryRejectedCall(htaskCallee, dwTickCount, dwRejectType);
|
|
TraceMsg(TF_SHDCONTROL, "shvMF RRC returned %x", hr);
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "shvMF RRC returning 0xffffffff");
|
|
return 0xffffffff;
|
|
}
|
|
};
|
|
|
|
virtual DWORD __stdcall MessagePending(
|
|
IN HTASK htaskCallee,
|
|
IN DWORD dwTickCount,
|
|
IN DWORD dwPendingType)
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "shv MF MessagePending htaskCallee=%x, dwTickCount=%x, dwPendingType=%x",
|
|
htaskCallee,
|
|
dwTickCount,
|
|
dwPendingType);
|
|
|
|
if (_lpMFOld)
|
|
{
|
|
HRESULT hr = _lpMFOld->MessagePending(htaskCallee, dwTickCount, dwPendingType);
|
|
TraceMsg(TF_SHDCONTROL, "shvMF RRC returned %x", hr);
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "shvMF MP returning PENDINGMSG_WAITDEFPROCESS");
|
|
return PENDINGMSG_WAITDEFPROCESS;
|
|
}
|
|
};
|
|
|
|
CMsgFilter() : _cRef(1)
|
|
{
|
|
ASSERT(_lpMFOld == NULL);
|
|
};
|
|
|
|
BOOL Initialize()
|
|
{
|
|
BOOL bResult = CoRegisterMessageFilter((LPMESSAGEFILTER)this, &_lpMFOld) != S_FALSE;
|
|
TraceMsg(TF_SHDCONTROL, "shv Previous message filter is %lx", _lpMFOld);
|
|
return bResult;
|
|
};
|
|
|
|
void UnInitialize()
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "shv MF Uninitializing, previous message filter = %x", _lpMFOld);
|
|
CoRegisterMessageFilter(_lpMFOld, NULL);
|
|
|
|
// we shouldn't ever get called again, but after 30 minutes
|
|
// of automation driving we once hit a function call above
|
|
// and we dereferenced this old pointer and page faulted.
|
|
|
|
ATOMICRELEASE(_lpMFOld);
|
|
};
|
|
|
|
protected:
|
|
int _cRef;
|
|
LPMESSAGEFILTER _lpMFOld;
|
|
};
|
|
|
|
|
|
CWebBrowserOC::CWebBrowserOC(IUnknown* punkOuter, LPCOBJECTINFO poi) :
|
|
SUPERCLASS(punkOuter, poi, c_averbsSV, c_averbsDesignSV)
|
|
{
|
|
TraceMsg(TF_SHDLIFE, "ctor CWebBrowserOC %x", this);
|
|
|
|
// flag special so we only try to load browseui once
|
|
_hBrowseUI = HMODULE_NOTLOADED;
|
|
}
|
|
|
|
BOOL CWebBrowserOC::_InitializeOC(IUnknown *punkOuter)
|
|
{
|
|
// we used a zero-init memory allocator, so everything else is NULL.
|
|
// check to be sure:
|
|
ASSERT(!_fInit);
|
|
|
|
// By default, we're visible. Everything else can default to FALSE.
|
|
//
|
|
_fVisible = 1;
|
|
|
|
// CShellOcx holds the default event source which is DIID_DWebBrowserEvents2
|
|
m_cpWB1Events.SetOwner(_GetInner(), &DIID_DWebBrowserEvents);
|
|
|
|
// some stuff we want to set up now. we're a WebBrowser, so create the
|
|
// IShellBrowser now. We need an aggregated automation object before
|
|
// we do that.
|
|
CIEFrameAuto_CreateInstance(SAFECAST(this, IOleControl*), &_pauto);
|
|
if (_pauto)
|
|
{
|
|
// Cache some interfaces of CIEFrameAuto.
|
|
//
|
|
// Since we aggregate CIEFrameAuto, this will increase our refcount.
|
|
// We cannot release this interface and expect it to work, so we
|
|
// call release on ourself to remove the refcount cycle.
|
|
//
|
|
// Since we ourselves may be aggregated and we always want to get
|
|
// CIEFrameAuto's interface and not our aggregator's, we delay
|
|
// setting up punkOuter until below.
|
|
//
|
|
_pauto->QueryInterface(IID_PPV_ARG(IWebBrowser2, &_pautoWB2));
|
|
ASSERT(_pautoWB2);
|
|
Release();
|
|
|
|
_pauto->QueryInterface(IID_PPV_ARG(IExpDispSupport, &_pautoEDS));
|
|
ASSERT(_pautoEDS);
|
|
Release();
|
|
}
|
|
|
|
// Now set up our aggregator's punkOuter
|
|
if (punkOuter)
|
|
{
|
|
CAggregatedUnknown::_SetOuter(punkOuter);
|
|
}
|
|
|
|
// postpone initialization of stuff that may be persisted
|
|
// until InitNew is called.
|
|
|
|
// Were we successful? (we don't have to free this
|
|
// here on failure, cuz we'll free them on delete)
|
|
return (NULL!=_pauto);
|
|
}
|
|
|
|
CWebBrowserOC::~CWebBrowserOC()
|
|
{
|
|
TraceMsg(TF_SHDLIFE, "dtor CWebBrowserOC %x", this);
|
|
|
|
ASSERT(!_fDidRegisterAsBrowser);
|
|
_UnregisterWindow(); // Last Chance - should have been done in InplaceDeactivate
|
|
|
|
if (_psb) {
|
|
ATOMICRELEASET(_psb, CWebBrowserSB);
|
|
}
|
|
|
|
ATOMICRELEASE(_plinkA);
|
|
|
|
// We need to release these cached interface pointers.
|
|
//
|
|
// Since we cached them before setting up our outer-aggregation,
|
|
// we need to un-outer-aggregate ourself first.
|
|
//
|
|
// Since we aggregate CIEFrameAuto (where these come from) we need
|
|
// to AddRef ourself before releasing. Fortunately, this is done for us
|
|
// by CAggregatedUnknown::Release (it bumps _cRef to 1000).
|
|
//
|
|
CAggregatedUnknown::_SetOuter(CAggregatedUnknown::_GetInner());
|
|
ATOMICRELEASE(_pautoWB2);
|
|
ATOMICRELEASE(_pautoEDS);
|
|
|
|
ATOMICRELEASE(_pauto);
|
|
|
|
if (_hmemSB) {
|
|
GlobalFree(_hmemSB);
|
|
_hmemSB = NULL;
|
|
}
|
|
|
|
if (_hBrowseUI != 0 && _hBrowseUI != HMODULE_NOTLOADED)
|
|
FreeLibrary(_hBrowseUI);
|
|
}
|
|
|
|
|
|
|
|
IStream *CWebBrowserSB::v_GetViewStream(LPCITEMIDLIST pidl, DWORD grfMode, LPCWSTR pwszName)
|
|
{
|
|
TCHAR szName[MAX_PATH];
|
|
SHUnicodeToTChar(pwszName, szName, ARRAYSIZE(szName));
|
|
return GetViewStream(pidl, grfMode, szName, REGSTR_PATH_EXPLORER TEXT("\\OCXStreamMRU"), TEXT("OCXStreams"));
|
|
}
|
|
|
|
void CWebBrowserOC::_InitDefault()
|
|
{
|
|
if (_fInit)
|
|
{
|
|
IPSMSG(TEXT("_InitDefault already initialized"));
|
|
return;
|
|
}
|
|
_fInit = TRUE;
|
|
|
|
// Different versions of the control get different defaults.
|
|
if (_pObjectInfo->lVersion == VERSION_1)
|
|
{
|
|
// AOL 3.0 compatibility: register as a browser window on InPlaceActivate
|
|
_fShouldRegisterAsBrowser = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// we use a zero-init memory allocator, so everything else is NULL.
|
|
ASSERT(FALSE == _fShouldRegisterAsBrowser);
|
|
}
|
|
|
|
_size.cx = DEF_WIDTH;
|
|
_size.cy = DEF_HEIGHT;
|
|
_sizeHIM = _size;
|
|
PixelsToMetric(&_sizeHIM);
|
|
|
|
_fs.ViewMode = FVM_ICON;
|
|
_fs.fFlags = FWF_AUTOARRANGE | FWF_NOCLIENTEDGE;
|
|
|
|
}
|
|
|
|
void CWebBrowserOC::_RegisterWindow()
|
|
{
|
|
if (!_fDidRegisterAsBrowser && _pipsite && _fShouldRegisterAsBrowser)
|
|
{
|
|
ITargetFrame2 *ptgf;
|
|
HRESULT hr;
|
|
|
|
if (SUCCEEDED(QueryInterface(IID_PPV_ARG(ITargetFrame2, &ptgf))))
|
|
{
|
|
IUnknown *pUnkParent;
|
|
|
|
hr = ptgf->GetParentFrame(&pUnkParent);
|
|
if (SUCCEEDED(hr) && pUnkParent != NULL)
|
|
{
|
|
pUnkParent->Release();
|
|
}
|
|
else
|
|
{
|
|
IShellWindows* psw = WinList_GetShellWindows(TRUE);
|
|
if (psw)
|
|
{
|
|
IDispatch* pid;
|
|
|
|
if (SUCCEEDED(ptgf->QueryInterface(IID_PPV_ARG(IDispatch, &pid))))
|
|
{
|
|
psw->Register(pid, PtrToLong(_hwnd), SWC_3RDPARTY, &_cbCookie);
|
|
_fDidRegisterAsBrowser = 1;
|
|
pid->Release();
|
|
}
|
|
psw->Release();
|
|
}
|
|
}
|
|
ptgf->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWebBrowserOC::_UnregisterWindow()
|
|
{
|
|
if (_fDidRegisterAsBrowser)
|
|
{
|
|
IShellWindows* psw = NULL;
|
|
|
|
psw = WinList_GetShellWindows(TRUE);
|
|
if (psw)
|
|
{
|
|
psw->Revoke(_cbCookie);
|
|
_fDidRegisterAsBrowser = 0;
|
|
psw->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::Draw(
|
|
DWORD dwDrawAspect,
|
|
LONG lindex,
|
|
void *pvAspect,
|
|
DVTARGETDEVICE *ptd,
|
|
HDC hdcTargetDev,
|
|
HDC hdcDraw,
|
|
LPCRECTL lprcBounds,
|
|
LPCRECTL lprcWBounds,
|
|
BOOL ( __stdcall *pfnContinue )(ULONG_PTR dwContinue),
|
|
ULONG_PTR dwContinue)
|
|
{
|
|
IS_INITIALIZED;
|
|
|
|
HRESULT hres;
|
|
|
|
IVOMSG3(TEXT("Draw called"), lprcBounds->top, lprcBounds->bottom);
|
|
IViewObject *pvo;
|
|
if (_psb && _psb->GetShellView() &&
|
|
SUCCEEDED(_psb->GetShellView()->QueryInterface(IID_PPV_ARG(IViewObject, &pvo))))
|
|
{
|
|
hres = pvo->Draw(dwDrawAspect, lindex, pvAspect, ptd, hdcTargetDev, hdcDraw,
|
|
lprcBounds, lprcWBounds, pfnContinue, dwContinue);
|
|
pvo->Release();
|
|
if (SUCCEEDED(hres))
|
|
return hres;
|
|
}
|
|
|
|
// If we don't have a shell view, or if it couldn't draw, then we draw ourselves.
|
|
// (if we're in design mode).
|
|
//
|
|
if (_IsDesignMode())
|
|
{
|
|
FillRect(hdcDraw, (RECT*) lprcBounds, (HBRUSH)GetStockObject(BLACK_BRUSH));
|
|
|
|
SIZE size = { ABS( lprcBounds->right - lprcBounds->left ),
|
|
ABS( lprcBounds->bottom - lprcBounds->top ) };
|
|
|
|
HBITMAP hImage;
|
|
HDC hdcTmp = CreateCompatibleDC( hdcDraw );
|
|
HMODULE hBrowseUI;
|
|
|
|
hBrowseUI = _GetBrowseUI();
|
|
if ( hBrowseUI )
|
|
hImage = LoadBitmap( hBrowseUI, MAKEINTRESOURCE( IDB_IEBRAND ));
|
|
else
|
|
hImage = NULL;
|
|
|
|
// hdcDraw may be a metafile, in which case the CreateCompatibleDC call will fail.
|
|
//
|
|
if ( !hdcTmp )
|
|
{
|
|
hdcTmp = CreateCompatibleDC( hdcTargetDev ); // Okay if hdcTargetDev == NULL
|
|
}
|
|
|
|
if (hdcTmp)
|
|
{
|
|
if ( hImage )
|
|
{
|
|
BITMAP bm;
|
|
POINT ptOriginDest; // origin of destination
|
|
SIZE sizeDest;
|
|
POINT ptOriginSrc = { 0, 0 };
|
|
SIZE sizeSrc;
|
|
|
|
GetObject( hImage, sizeof( bm ), &bm );
|
|
|
|
HGDIOBJ hPrev = SelectObject( hdcTmp, hImage );
|
|
|
|
// Yes, this looks wrong, but it's right. We only want the first frame
|
|
// of the brand bitmap, and the frames are stacked vertically.
|
|
//
|
|
sizeSrc.cx = sizeSrc.cy = bm.bmWidth;
|
|
|
|
// This code centers the bitmap while preserving its aspect ratio.
|
|
//
|
|
if ( size.cx > size.cy )
|
|
{
|
|
// if destination is wider than tall,
|
|
//
|
|
ptOriginDest.x = lprcBounds->left + size.cx/2 - size.cy/2;
|
|
ptOriginDest.y = lprcBounds->top;
|
|
sizeDest.cx = size.cy;
|
|
sizeDest.cy = lprcBounds->bottom - lprcBounds->top >= 0 ? size.cy : -size.cy;
|
|
}
|
|
else
|
|
{
|
|
// else destination is taller than wide
|
|
//
|
|
ptOriginDest.x = lprcBounds->left;
|
|
ptOriginDest.y = lprcBounds->bottom - lprcBounds->top >= 0
|
|
? ( lprcBounds->top + size.cy/2 - size.cx/2 )
|
|
: -( lprcBounds->top + size.cy/2 - size.cx/2 );
|
|
sizeDest.cx = size.cx;
|
|
sizeDest.cy = lprcBounds->bottom - lprcBounds->top >= 0 ? size.cx : -size.cx;
|
|
}
|
|
|
|
StretchBlt( hdcDraw,
|
|
ptOriginDest.x, ptOriginDest.y,
|
|
sizeDest.cx, sizeDest.cy,
|
|
hdcTmp,
|
|
ptOriginSrc.x, ptOriginSrc.y,
|
|
sizeSrc.cx, sizeSrc.cy,
|
|
SRCCOPY );
|
|
|
|
SelectObject( hdcTmp, hPrev );
|
|
DeleteObject( hImage );
|
|
}
|
|
|
|
DeleteDC( hdcTmp );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
return SUPERCLASS::Draw(dwDrawAspect, lindex, pvAspect, ptd, hdcTargetDev, hdcDraw,
|
|
lprcBounds, lprcWBounds, pfnContinue, dwContinue);
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::GetColorSet(DWORD dwAspect, LONG lindex,
|
|
void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDev,
|
|
LOGPALETTE **ppColorSet)
|
|
{
|
|
IViewObject *pvo;
|
|
|
|
if (_psb && _psb->GetShellView() &&
|
|
SUCCEEDED(_psb->GetShellView()->QueryInterface(IID_PPV_ARG(IViewObject, &pvo))))
|
|
{
|
|
HRESULT hres = pvo->GetColorSet(dwAspect, lindex, pvAspect, ptd,
|
|
hicTargetDev, ppColorSet);
|
|
|
|
pvo->Release();
|
|
|
|
if (SUCCEEDED(hres))
|
|
return hres;
|
|
}
|
|
|
|
return SUPERCLASS::GetColorSet(dwAspect, lindex, pvAspect, ptd,
|
|
hicTargetDev, ppColorSet);
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::SetExtent(DWORD dwDrawAspect, SIZEL *psizel)
|
|
{
|
|
HRESULT hr = SUPERCLASS::SetExtent(dwDrawAspect, psizel);
|
|
if ( FAILED( hr ))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// If oc < inplace then forward SetExtent through to docobject.
|
|
// If docobject is already inplace active, SetExtent is meaningless.
|
|
//
|
|
|
|
if (_nActivate < OC_INPLACEACTIVE)
|
|
{
|
|
IPrivateOleObject * pPrivOle = NULL;
|
|
if ( _psb && _psb->GetShellView() &&
|
|
SUCCEEDED(_psb->GetShellView()->QueryInterface(IID_PPV_ARG(IPrivateOleObject, &pPrivOle))))
|
|
{
|
|
// we have an ole object, delegate downwards...
|
|
hr = pPrivOle->SetExtent( dwDrawAspect, psizel );
|
|
pPrivOle->Release();
|
|
}
|
|
|
|
_dwDrawAspect = dwDrawAspect;
|
|
// the size is already cached in _sizeHIM in our base class by the SUPERCLASS::SetExtent()
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// Called after the client site has been set so we can process
|
|
// stuff in the correct order
|
|
//
|
|
void CWebBrowserOC::_OnSetClientSite()
|
|
{
|
|
// Until we have a client site we can't determine toplevelness.
|
|
//
|
|
if (_pcli)
|
|
{
|
|
BOOL fFoundBrowserService = FALSE;
|
|
IBrowserService *pbsTop;
|
|
|
|
if (SUCCEEDED(IUnknown_QueryService(_pcli, SID_STopLevelBrowser, IID_PPV_ARG(IBrowserService, &pbsTop))))
|
|
{
|
|
fFoundBrowserService = TRUE;
|
|
pbsTop->Release();
|
|
}
|
|
|
|
// if nobody above us supports IBrowserService, we must be toplevel.
|
|
if (!fFoundBrowserService)
|
|
_fTopLevel = TRUE;
|
|
|
|
|
|
// If we haven't created CWebBrowserSB, do so now.
|
|
// We do this before our superclass OnSetClientSite
|
|
// because shembed will create the window which
|
|
// requires _psb's existence.
|
|
//
|
|
// NOTE: We do this here instead of _Initialize because
|
|
// CBaseBrowser will QI us for interfaces during this call.
|
|
// If we're in the middle of our CreateInstance function
|
|
// and we've been aggregated, we pass the QI to _punkAgg
|
|
// who faults because we haven't returned from CoCreateInstance.
|
|
//
|
|
// NOTE: We now destroy our window on SetClientSite(NULL)
|
|
// which frees ths _psb, so we should create this every time.
|
|
//
|
|
if (!_psb)
|
|
{
|
|
// Give _psb our inner unknown so we never get interfaces
|
|
// from whoever may aggregate us. _GetInner gives us
|
|
// first crack at QueryInterface so we get the correct
|
|
// IWebBrowser implementation.
|
|
//
|
|
_psb = new CWebBrowserSB(CAggregatedUnknown::_GetInner(), this);
|
|
|
|
// if we don't get _psb we're totally hosed...
|
|
//
|
|
if (_psb)
|
|
{
|
|
_psb->_fldBase._fld._fs = _fs;
|
|
// tell _psb if it's top-level or not
|
|
//
|
|
if (_fTopLevel)
|
|
{
|
|
_psb->SetTopBrowser();
|
|
}
|
|
|
|
// CBaseBrowser assumes SVUIA_ACTIVATE_FOCUS, tell it what we really are
|
|
//
|
|
ASSERT(OC_DEACTIVE == _nActivate); // we shouldn't be activated yet
|
|
_psb->_UIActivateView(SVUIA_DEACTIVATE);
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "Couldn't create _psb. We are hosed!");
|
|
// don't let the window get created by our superclass,
|
|
// as we can't do anything anyway...
|
|
//
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Tell our aggregatee that their cached window is invalid
|
|
//
|
|
IEFrameAuto * piefa;
|
|
if (EVAL(SUCCEEDED(_pauto->QueryInterface(IID_PPV_ARG(IEFrameAuto, &piefa)))))
|
|
{
|
|
piefa->SetOwnerHwnd(NULL);
|
|
piefa->Release();
|
|
}
|
|
|
|
if (_lpMF)
|
|
{
|
|
IMessageFilter* lpMF = _lpMF;
|
|
_lpMF = NULL;
|
|
((CMsgFilter *)lpMF)->UnInitialize();
|
|
EVAL(lpMF->Release() == 0);
|
|
}
|
|
|
|
// Decrement the browser session count
|
|
//
|
|
if (_fIncrementedSessionCount)
|
|
{
|
|
SetQueryNetSessionCount(SESSION_DECREMENT);
|
|
_fIncrementedSessionCount = FALSE; // In case this instance is reused.
|
|
}
|
|
}
|
|
|
|
SUPERCLASS::_OnSetClientSite();
|
|
|
|
if (_pcli)
|
|
{
|
|
VARIANT_BOOL fAmbient = VARIANT_FALSE;
|
|
HWND hwndParent = NULL;
|
|
// We init the local properties using ambients if available
|
|
// If this fails, fAmbient will be left at VARIANT_FALSE which is what we need for the next
|
|
// statement.
|
|
//
|
|
if (SUPERCLASS::_GetAmbientProperty(DISPID_AMBIENT_OFFLINEIFNOTCONNECTED, VT_BOOL, &fAmbient))
|
|
{
|
|
put_Offline(fAmbient);
|
|
}
|
|
|
|
// If top-level and not offline, increment the browser session count.
|
|
//
|
|
if (_fTopLevel && !fAmbient)
|
|
{
|
|
SetQueryNetSessionCount(SESSION_INCREMENT_NODEFAULTBROWSERCHECK);
|
|
_fIncrementedSessionCount = TRUE;
|
|
}
|
|
|
|
if (SUPERCLASS::_GetAmbientProperty(DISPID_AMBIENT_SILENT, VT_BOOL, &fAmbient))
|
|
{
|
|
put_Silent(fAmbient);
|
|
}
|
|
|
|
// After the parent window has been set, check to see if it is on the same thread as us.
|
|
// If not, we have a cross-thread container and we need a message filter.
|
|
//
|
|
if ( _fTopLevel // If we're top level
|
|
&& _hwnd // and we have an hwnd (we should)
|
|
&& (hwndParent = GetParent( _hwnd ) ) // and we have a parent window
|
|
// and the parent window is on a different thread
|
|
&& GetWindowThreadProcessId( _hwnd, NULL ) != GetWindowThreadProcessId( hwndParent, NULL ))
|
|
{
|
|
if (!_lpMF)
|
|
{
|
|
/*
|
|
* Create a message filter here to reject RPC-reentrant calls.
|
|
*/
|
|
_lpMF = new CMsgFilter();
|
|
|
|
if (_lpMF && !(((CMsgFilter *)_lpMF)->Initialize()))
|
|
{
|
|
ATOMICRELEASE(_lpMF);
|
|
}
|
|
TraceMsg(TF_SHDCONTROL, "shv Registering message filter (%lx) for RPC-reentrancy", _lpMF);
|
|
}
|
|
}
|
|
|
|
|
|
// if we have a pending navigation from IPS::Load, do it now.
|
|
//
|
|
if (_fNavigateOnSetClientSite && _plinkA && _psb)
|
|
{
|
|
//
|
|
// We hit this code if this OC is IPersistStream::Loaded before
|
|
// the client site is set.
|
|
//
|
|
LPITEMIDLIST pidl;
|
|
if (SUCCEEDED(_plinkA->GetIDList(&pidl)) && pidl)
|
|
{
|
|
_BrowseObject(pidl);
|
|
ILFree(pidl);
|
|
}
|
|
|
|
_fNavigateOnSetClientSite = FALSE;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
STDAPI CWebBrowserOC_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
|
|
{
|
|
HRESULT hres;
|
|
|
|
hres = E_OUTOFMEMORY;
|
|
CWebBrowserOC* psvo = new CWebBrowserOC(NULL, poi);
|
|
if (psvo)
|
|
{
|
|
if (!psvo->_InitializeOC(punkOuter))
|
|
{
|
|
psvo->Release();
|
|
}
|
|
else
|
|
{
|
|
*ppunk = psvo->_GetInner();
|
|
hres = S_OK;
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
LRESULT CWebBrowserOC::_OnPaintPrint(HDC hdcPrint)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hdc = hdcPrint ? hdcPrint : BeginPaint(_hwnd, &ps);
|
|
RECT rc;
|
|
GetClientRect(_hwnd, &rc);
|
|
DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_ADJUST|BF_RECT|BF_SOFT);
|
|
DrawText(hdc, hdcPrint ? TEXT("Print") : TEXT("Paint"),
|
|
-1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
if (!hdcPrint)
|
|
{
|
|
EndPaint(_hwnd, &ps);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::_BrowseObject(LPCITEMIDLIST pidlBrowseTo)
|
|
{
|
|
if (_psb)
|
|
return _psb->BrowseObject(pidlBrowseTo, SBSP_SAMEBROWSER | SBSP_ABSOLUTE);
|
|
|
|
// if no _psb at this point, container did not
|
|
// honor OLEMISC_SETCLIENTSITEFIRST bit, so silently
|
|
// fail instead of trying to make this work
|
|
ASSERT(FALSE);
|
|
return E_FAIL;
|
|
}
|
|
|
|
LRESULT CWebBrowserOC::_OnCreate(LPCREATESTRUCT lpcs)
|
|
{
|
|
LRESULT lres;
|
|
|
|
if (_psb)
|
|
{
|
|
ASSERT(_hwnd);
|
|
_psb->_SetWindow(_hwnd);
|
|
|
|
lres = _psb->OnCreate(NULL);
|
|
}
|
|
else
|
|
{
|
|
lres = (LRESULT)-1;
|
|
}
|
|
|
|
//
|
|
// If IPersistStream::Load has stored away a block of stream for
|
|
// toolbars, this is the time to use it.
|
|
//
|
|
if (_hmemSB)
|
|
{
|
|
GlobalFree(_hmemSB);
|
|
_hmemSB = NULL;
|
|
}
|
|
|
|
return lres;
|
|
}
|
|
|
|
//
|
|
// This is a virtual function defined in CShellEmbedding class, which
|
|
// is called when all but WM_NCCREATE and WM_NCDESTROY messages are
|
|
// dispatched to the our "Shell Embedding" window. It's important
|
|
// to remember that we pass this window handle to the constructor of
|
|
// CWebBrowserSB (which calls the constructor of CBaseBrowser).
|
|
// That's why we forward all messages to _psb->WndProcBS. (SatoNa)
|
|
//
|
|
LRESULT CWebBrowserOC::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT lres = 0L;
|
|
|
|
if (WM_CREATE == uMsg)
|
|
{
|
|
// We need first crack at this message before
|
|
// forwarding it along to _psb (which we do
|
|
// in this _OnCreate call)
|
|
return _OnCreate((LPCREATESTRUCT)lParam);
|
|
}
|
|
|
|
// only let _psb look at it if the message is not reserved for us
|
|
if (!IsInRange(uMsg, CWM_RESERVEDFORWEBBROWSER_FIRST, CWM_RESERVEDFORWEBBROWSER_LAST))
|
|
{
|
|
BOOL fDontForward = FALSE;
|
|
|
|
// destroy bottom up for these
|
|
switch (uMsg)
|
|
{
|
|
case WM_DESTROY:
|
|
case WM_CLOSE:
|
|
SUPERCLASS::v_WndProc(hwnd, uMsg, wParam, lParam);
|
|
fDontForward = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// This AssertMsg will help debugging IE v4.1 bug 12931.
|
|
//
|
|
// Comment out assert now that we don't create _psb at constructor time. (?)
|
|
//AssertMsg((BOOL)_psb, "WBOC::v_WndProc _psb==NULL! uMsg=%x", uMsg);
|
|
|
|
if (_psb)
|
|
{
|
|
lres = _psb->WndProcBS(hwnd, uMsg, wParam, lParam);
|
|
|
|
// Due to aggregation of IEFrameAuto, _psb is holding references
|
|
// to us, so we need to break the cycle.
|
|
// _psb may have been freed above. Double check it.
|
|
//
|
|
if (uMsg == WM_DESTROY && _psb)
|
|
{
|
|
_psb->ReleaseShellView();
|
|
_psb->ReleaseShellExplorer();
|
|
ATOMICRELEASET(_psb, CWebBrowserSB);
|
|
}
|
|
}
|
|
if (uMsg >= WM_USER || fDontForward)
|
|
{
|
|
return lres;
|
|
}
|
|
}
|
|
|
|
switch(uMsg)
|
|
{
|
|
/* these are handled by CBaseBrowser only */
|
|
case WM_NOTIFY:
|
|
return lres;
|
|
|
|
case WM_SETCURSOR:
|
|
if (lres) {
|
|
return lres;
|
|
}
|
|
goto DoDefault;
|
|
|
|
DoDefault:
|
|
default:
|
|
return SUPERCLASS::v_WndProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
return 0L;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::Close(DWORD dwSaveOption)
|
|
{
|
|
if (_psb)
|
|
{
|
|
_psb->_CancelPendingNavigation();
|
|
}
|
|
|
|
if (_pauto)
|
|
{
|
|
IWebBrowserPriv * pWBPriv;
|
|
|
|
HRESULT hr = _pauto->QueryInterface(IID_PPV_ARG(IWebBrowserPriv, &pWBPriv));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pWBPriv->OnClose();
|
|
pWBPriv->Release();
|
|
}
|
|
}
|
|
|
|
return SUPERCLASS::Close(dwSaveOption);
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
|
|
{
|
|
IOOMSG(TEXT("SetHostNames"));
|
|
|
|
// We are not interested in host name
|
|
// ...well ... maybe a little. this turns out to be the best place to
|
|
// do an apphack for VC 5.0. VC 5.0 has a bug where it calls Release()
|
|
// one too many times. the only good way to detect being hosted in the
|
|
// offending container is to check the szContainerApp in SetHostNames!
|
|
// ...chrisfra 8/14/97, bug 30428
|
|
// NOTE: Mike Colee of VC verified their bug and will put a Raid bug in
|
|
// their database including how to signal that a new version works by
|
|
// changing szContainerApp string.
|
|
if (_fTopLevel && szContainerApp && !StrCmpW(szContainerApp, L"DevIV Package"))
|
|
{
|
|
AddRef();
|
|
}
|
|
return SUPERCLASS::SetHostNames(szContainerApp, szContainerObj);
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::DoVerb(
|
|
LONG iVerb,
|
|
LPMSG lpmsg,
|
|
IOleClientSite *pActiveSite,
|
|
LONG lindex,
|
|
HWND hwndParent,
|
|
LPCRECT lprcPosRect)
|
|
{
|
|
IS_INITIALIZED;
|
|
|
|
_pmsgDoVerb = lpmsg;
|
|
|
|
HRESULT hr = SUPERCLASS::DoVerb(iVerb, lpmsg, pActiveSite, lindex, hwndParent, lprcPosRect);
|
|
|
|
_pmsgDoVerb = NULL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
// *** IPersistStreamInit ***
|
|
|
|
// in order to have upgrade and downgrade compatibility in stream formats
|
|
// we can't have any size assumptions in this code. Extra data streamed
|
|
// after our PersistSVOCX structure must be referenced by a dwOffX offset
|
|
// so the downgrade case knows where to start reading from.
|
|
//
|
|
// since we always write out a stream that's downward compatible, we don't
|
|
// need to folow the "source compatible" rule of: reading an old stream
|
|
// with an old CLSID WebBrowser implies that when we save, we need to
|
|
// save using the old stream format.
|
|
//
|
|
typedef struct _PersistSVOCX
|
|
{
|
|
struct _tagIE30 {
|
|
DWORD cbSize;
|
|
SIZE sizeObject; // IE3 saves as PIXELS, IE4 saves as HIMETRIC
|
|
FOLDERSETTINGS fs;
|
|
long lAutoSize; // IE3, no longer used
|
|
DWORD fColorsSet; // IE3, no longer used
|
|
COLORREF clrBack; // IE3, no longer used
|
|
COLORREF clrFore; // IE3, no longer used
|
|
DWORD dwOffPersistLink;
|
|
long lAutoSizePercentage; // IE3, no longer used
|
|
} ie30;
|
|
struct _tagIE40 {
|
|
DWORD dwExtra;
|
|
BOOL bRestoreView;
|
|
SHELLVIEWID vid;
|
|
DWORD fFlags;
|
|
DWORD dwVersion;
|
|
} ie40;
|
|
} PersistSVOCX;
|
|
|
|
//
|
|
// Flags for dwExtra. Having a flag indicate that we have some extra
|
|
// streamed data after this structure + persisted link.
|
|
//
|
|
// NOTE: All data stored this way (instead of storing an offset to
|
|
// the data, such as dwOffPersistLink) will be lost on downgrade
|
|
// cases and cases where we have to emulate old stream formats.
|
|
//
|
|
#define SVO_EXTRA_TOOLBARS 0x00000001
|
|
|
|
// Random flags we need to persist
|
|
#define SVO_FLAGS_OFFLINE 0x00000001
|
|
#define SVO_FLAGS_SILENT 0x00000002
|
|
#define SVO_FLAGS_REGISTERASBROWSER 0x00000004
|
|
#define SVO_FLAGS_REGISTERASDROPTGT 0x00000008
|
|
|
|
#define SVO_VERSION 0 // increment for upgrade changes when size doesn't change
|
|
|
|
HRESULT CWebBrowserOC::Load(IStream *pstm)
|
|
{
|
|
IPSMSG(TEXT("Load"));
|
|
// Load _size
|
|
ULONG cbRead;
|
|
PersistSVOCX sPersist;
|
|
HRESULT hres, hresNavigate = E_FAIL;
|
|
DWORD dwExtra = 0;
|
|
|
|
// It is illegal to call Load or InitNew more than once
|
|
if (_fInit)
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "shv IPersistStream::Load called when ALREADY INITIALIZED!");
|
|
ASSERT(FALSE);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// we need an IShellLink to read into
|
|
if (_plinkA == NULL)
|
|
{
|
|
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &_plinkA));
|
|
if (FAILED(hres))
|
|
return hres;
|
|
}
|
|
|
|
// remember our starting location
|
|
ULARGE_INTEGER liStart;
|
|
//ULARGE_INTEGER liEnd;
|
|
LARGE_INTEGER liMove;
|
|
liMove.LowPart = liMove.HighPart = 0;
|
|
hres = pstm->Seek(liMove, STREAM_SEEK_CUR, &liStart);
|
|
if (FAILED(hres))
|
|
{
|
|
return hres;
|
|
}
|
|
|
|
// Zero initialize our struct
|
|
ZeroMemory(&sPersist, SIZEOF(sPersist));
|
|
|
|
hres = pstm->Read(&sPersist, SIZEOF(DWORD), &cbRead);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
// Validate the data
|
|
if (cbRead != SIZEOF(DWORD) ||
|
|
sPersist.ie30.cbSize < SIZEOF(sPersist.ie30))
|
|
{
|
|
TraceMsg(DM_ERROR, "Someone is asking us to read the wrong thing.");
|
|
hres = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
DWORD cbSizeToRead = sPersist.ie30.cbSize;
|
|
if (cbSizeToRead > SIZEOF(sPersist))
|
|
{
|
|
// must be a newer struct, only read what we know (ie, don't trash the stack!)
|
|
cbSizeToRead = SIZEOF(sPersist);
|
|
}
|
|
cbSizeToRead -= SIZEOF(DWORD); // remove what we've already read
|
|
hres = pstm->Read(&sPersist.ie30.sizeObject, cbSizeToRead, &cbRead);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if (cbRead != cbSizeToRead)
|
|
{
|
|
hres = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
// read ie30 data
|
|
//
|
|
if (EVAL(sPersist.ie30.cbSize >= SIZEOF(sPersist.ie30)))
|
|
{
|
|
_size = sPersist.ie30.sizeObject;
|
|
_fs = sPersist.ie30.fs;
|
|
|
|
// IE3 saved size in pixels IE4 saves size in HIM already
|
|
//
|
|
_sizeHIM = _size;
|
|
if (sPersist.ie30.cbSize == SIZEOF(sPersist.ie30) ||
|
|
sPersist.ie30.cbSize == SIZEOF(sPersist) - SIZEOF(sPersist.ie40.dwVersion)) // handle upgrade
|
|
{
|
|
// Size is in pixels. Adjust _sizeHIM to Hi Metric.
|
|
PixelsToMetric(&_sizeHIM);
|
|
}
|
|
else
|
|
{
|
|
// Size is in Hi Metric. Adjust _size to Pixels.
|
|
MetricToPixels(&_size);
|
|
}
|
|
|
|
if (_psb) // if no _psb then container ignored OLEMISC_SETCLIENTSITEFIRST
|
|
_psb->_fldBase._fld._fs = _fs;
|
|
|
|
// Load _plinkA
|
|
IPersistStream* ppstm;
|
|
hres = _plinkA->QueryInterface(IID_PPV_ARG(IPersistStream, &ppstm));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
ASSERT(sPersist.ie30.dwOffPersistLink >= sPersist.ie30.cbSize);
|
|
liMove.LowPart = liStart.LowPart + sPersist.ie30.dwOffPersistLink;
|
|
|
|
hres = pstm->Seek(liMove, STREAM_SEEK_SET, NULL);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = ppstm->Load(pstm);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
// We always save link info last,
|
|
// so remember where we are in the stream.
|
|
// Since we don't have more dwOff variables
|
|
// currently, don't bother remebering this...
|
|
//hres = pstm->Seek(liMove, STREAM_SEEK_CUR, &liEnd);
|
|
//if (SUCCEEDED(hres))
|
|
_fInit = TRUE;
|
|
|
|
// in case the target moved invoke link tracking (ignore errors)
|
|
_plinkA->Resolve(_hwnd, SLR_NO_UI);
|
|
|
|
// If we already have the client site,
|
|
// navigate now. Otherwise, navigate
|
|
// when the client site is set.
|
|
if (_pcli)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
if (SUCCEEDED(_plinkA->GetIDList(&pidl)) && pidl)
|
|
{
|
|
ASSERT(FALSE == _psb->_fAsyncNavigate);
|
|
_psb->_fAsyncNavigate = TRUE;
|
|
hresNavigate = _BrowseObject(pidl);
|
|
_psb->_fAsyncNavigate = FALSE;
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_fNavigateOnSetClientSite = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
ppstm->Release();
|
|
}
|
|
} // read ie30 data
|
|
|
|
|
|
// temp upgrade hack for older struct
|
|
if (sPersist.ie30.cbSize == SIZEOF(sPersist) - SIZEOF(sPersist.ie40.dwVersion))
|
|
{
|
|
// dwVersion field is already correct, update cbSize
|
|
// to pass below size check
|
|
sPersist.ie30.cbSize = SIZEOF(sPersist);
|
|
}
|
|
|
|
// read ie40 data
|
|
if (SUCCEEDED(hres) &&
|
|
sPersist.ie30.cbSize >= SIZEOF(sPersist))
|
|
{
|
|
if (_psb) // if no _psb then container ignored OLEMISC_SETCLIENTSITEFIRST
|
|
{
|
|
if (sPersist.ie40.bRestoreView)
|
|
{
|
|
_psb->_fldBase._fld._vidRestore = sPersist.ie40.vid;
|
|
// since we read the ie40 data, this is a cache hit
|
|
_psb->_fldBase._fld._dwViewPriority = VIEW_PRIORITY_CACHEHIT;
|
|
}
|
|
}
|
|
|
|
// We let ambients take precedence over what we have persisted
|
|
VARIANT_BOOL fAmbient;
|
|
if (SUPERCLASS::_GetAmbientProperty(DISPID_AMBIENT_OFFLINEIFNOTCONNECTED, VT_BOOL, &fAmbient))
|
|
{
|
|
put_Offline(fAmbient);
|
|
}
|
|
else
|
|
{
|
|
put_Offline((sPersist.ie40.fFlags & SVO_FLAGS_OFFLINE) ? -1 : FALSE);
|
|
}
|
|
if (SUPERCLASS::_GetAmbientProperty(DISPID_AMBIENT_SILENT, VT_BOOL, &fAmbient))
|
|
{
|
|
put_Silent(fAmbient);
|
|
}
|
|
else
|
|
{
|
|
put_Silent((sPersist.ie40.fFlags & SVO_FLAGS_SILENT) ? -1 : FALSE);
|
|
}
|
|
|
|
|
|
put_RegisterAsDropTarget(BOOL_TO_VARIANTBOOL(sPersist.ie40.fFlags & SVO_FLAGS_REGISTERASDROPTGT));
|
|
|
|
_fShouldRegisterAsBrowser = (sPersist.ie40.fFlags & SVO_FLAGS_REGISTERASBROWSER) ? TRUE : FALSE;
|
|
|
|
// remember this for later
|
|
dwExtra = sPersist.ie40.dwExtra;
|
|
}
|
|
else
|
|
{
|
|
// if CLSID_WebBrowser_V1 reads an old stream format,
|
|
// it means that we must write out an old stream format later
|
|
// remember this...
|
|
if (_pObjectInfo->lVersion == VERSION_1)
|
|
{
|
|
_fEmulateOldStream = TRUE;
|
|
}
|
|
} // read ie40 data
|
|
}
|
|
|
|
// if we read all the data then make sure we're at
|
|
// the end of the stream
|
|
if (SUCCEEDED(hres) && _fInit)
|
|
{
|
|
//liMove.LowPart = liEnd.LowPart;
|
|
//hres = pstm->Seek(liMove, STREAM_SEEK_SET, NULL);
|
|
|
|
// now we can read in extra streamed data if we have it
|
|
if (dwExtra & SVO_EXTRA_TOOLBARS)
|
|
{
|
|
DWORD dwTotal;
|
|
hres = pstm->Read(&dwTotal, SIZEOF(dwTotal), NULL);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
ASSERT(dwTotal >= SIZEOF(dwTotal));
|
|
dwTotal -= SIZEOF(dwTotal);
|
|
|
|
if (_hmemSB)
|
|
{
|
|
GlobalFree(_hmemSB);
|
|
}
|
|
|
|
_hmemSB = GlobalAlloc(GPTR, dwTotal);
|
|
if (_hmemSB)
|
|
{
|
|
hres = pstm->Read((BYTE*)_hmemSB, dwTotal, NULL);
|
|
}
|
|
else
|
|
{
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_OnLoaded(FAILED(hresNavigate));
|
|
|
|
if (SUCCEEDED(hres))
|
|
hres = S_OK; // convert S_FALSE to S_OK
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC_SavePersistData(IStream *pstm, SIZE* psizeObj,
|
|
FOLDERSETTINGS* pfs, IShellLinkA* plinkA, SHELLVIEWID* pvid,
|
|
BOOL fOffline, BOOL fSilent, BOOL fRegisterAsBrowser, BOOL fRegisterAsDropTarget,
|
|
BOOL fEmulateOldStream, DWORD *pdwExtra)
|
|
{
|
|
ULONG cbWritten;
|
|
PersistSVOCX sPersist;
|
|
HRESULT hres;
|
|
|
|
// This means that this instance of CWebBrowserOC was created using
|
|
// the ie30 CLSID and we were persisted from an old format stream.
|
|
// Under this scenario, we have to write out a stream format that
|
|
// can be read by the old ie30 object.
|
|
if (fEmulateOldStream && pdwExtra)
|
|
{
|
|
// The only data we stream out that can't be read back in by
|
|
// the old ie30 webbrowser is the dwExtra data.
|
|
*pdwExtra = 0;
|
|
}
|
|
|
|
|
|
ZeroMemory(&sPersist, SIZEOF(sPersist));
|
|
|
|
sPersist.ie30.cbSize = fEmulateOldStream ? SIZEOF(sPersist.ie30) : SIZEOF(sPersist);
|
|
sPersist.ie30.sizeObject = *psizeObj;
|
|
sPersist.ie30.fs = *pfs;
|
|
sPersist.ie30.dwOffPersistLink = SIZEOF(sPersist);
|
|
if (pvid)
|
|
{
|
|
sPersist.ie40.bRestoreView = TRUE;
|
|
sPersist.ie40.vid = *pvid;
|
|
}
|
|
sPersist.ie40.dwExtra = pdwExtra ? *pdwExtra : 0;
|
|
if (fOffline)
|
|
sPersist.ie40.fFlags |= SVO_FLAGS_OFFLINE;
|
|
if (fSilent)
|
|
sPersist.ie40.fFlags |= SVO_FLAGS_SILENT;
|
|
if (fRegisterAsBrowser)
|
|
sPersist.ie40.fFlags |= SVO_FLAGS_REGISTERASBROWSER;
|
|
if (fRegisterAsDropTarget)
|
|
sPersist.ie40.fFlags |= SVO_FLAGS_REGISTERASDROPTGT;
|
|
sPersist.ie40.dwVersion = SVO_VERSION;
|
|
|
|
hres = pstm->Write(&sPersist, SIZEOF(sPersist), &cbWritten);
|
|
IPSMSG3(TEXT("Save 1st Write(&_size) returned"), hres, cbWritten, sizeof(*psizeObj));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
// Save plinkA
|
|
ASSERT(plinkA);
|
|
IPersistStream* ppstm;
|
|
hres = plinkA->QueryInterface(IID_PPV_ARG(IPersistStream, &ppstm));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = ppstm->Save(pstm, TRUE);
|
|
IPSMSG2(TEXT("Save plink->Save() returned"), hres);
|
|
|
|
ppstm->Release();
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
BOOL CWebBrowserOC::_GetViewInfo(SHELLVIEWID* pvid)
|
|
{
|
|
BOOL bGotView = FALSE;
|
|
|
|
if (_psb)
|
|
{
|
|
if (_psb->GetShellView())
|
|
{
|
|
_psb->GetShellView()->GetCurrentInfo(&_fs);
|
|
}
|
|
else
|
|
{
|
|
_fs = _psb->_fldBase._fld._fs;
|
|
}
|
|
bGotView = FileCabinet_GetDefaultViewID2(&_psb->_fldBase, pvid);
|
|
}
|
|
|
|
return bGotView;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::Save(IStream *pstm, BOOL fClearDirty)
|
|
{
|
|
HRESULT hres;
|
|
LPITEMIDLIST pidl;
|
|
SHELLVIEWID vid;
|
|
BOOL bGotView;
|
|
VARIANT_BOOL fOffline, fSilent, fRegDT;
|
|
|
|
IPSMSG(TEXT("Save"));
|
|
IS_INITIALIZED;
|
|
|
|
pidl = NULL;
|
|
if (_psb)
|
|
pidl = _psb->_bbd._pidlCur;
|
|
|
|
// we need an IShellLink to save with
|
|
if (_plinkA == NULL)
|
|
{
|
|
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &_plinkA));
|
|
if (FAILED(hres))
|
|
return hres;
|
|
}
|
|
_plinkA->SetIDList(pidl);
|
|
|
|
bGotView = _GetViewInfo(&vid);
|
|
|
|
DWORD dwExtra = 0;
|
|
|
|
get_Offline(&fOffline);
|
|
get_Silent(&fSilent);
|
|
get_RegisterAsDropTarget(&fRegDT);
|
|
|
|
hres = CWebBrowserOC_SavePersistData(pstm, _fEmulateOldStream ? &_size : &_sizeHIM, &_fs, _plinkA,
|
|
(bGotView ? &vid : NULL),
|
|
fOffline, fSilent, _fShouldRegisterAsBrowser, fRegDT,
|
|
_fEmulateOldStream, &dwExtra);
|
|
|
|
ASSERT(!(dwExtra & SVO_EXTRA_TOOLBARS));
|
|
|
|
if (fClearDirty)
|
|
{
|
|
_fDirty = FALSE;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
void CWebBrowserOC::_OnLoaded(BOOL fUpdateBrowserReadyState)
|
|
{
|
|
IEFrameAuto * piefa;
|
|
if (SUCCEEDED(_pauto->QueryInterface(IID_PPV_ARG(IEFrameAuto, &piefa))))
|
|
{
|
|
piefa->put_DefaultReadyState(READYSTATE_COMPLETE, fUpdateBrowserReadyState);
|
|
piefa->Release();
|
|
}
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::InitNew(void)
|
|
{
|
|
IPSMSG(TEXT("InitNew"));
|
|
|
|
_InitDefault();
|
|
|
|
// On the InitNew case, we do want to update the browser's ready state
|
|
_OnLoaded(TRUE);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
// IPersistPropertyBag
|
|
|
|
static const struct {
|
|
LPOLESTR pName;
|
|
UINT flag;
|
|
} g_boolprops[] = {
|
|
{L"AutoArrange", FWF_AUTOARRANGE},
|
|
{L"NoClientEdge", FWF_NOCLIENTEDGE},
|
|
{L"AlignLeft", FWF_ALIGNLEFT},
|
|
{L"NoWebView", FWF_NOWEBVIEW},
|
|
{L"HideFileNames", FWF_HIDEFILENAMES},
|
|
{L"SingleClick", FWF_SINGLECLICKACTIVATE},
|
|
{L"SingleSelection", FWF_SINGLESEL},
|
|
{L"NoFolders", FWF_NOSUBFOLDERS},
|
|
{L"Transparent", FWF_TRANSPARENT},
|
|
};
|
|
|
|
HRESULT CWebBrowserOC::Load(IPropertyBag *pBag, IErrorLog *pErrorLog)
|
|
{
|
|
BOOL fOffline = FALSE;
|
|
BOOL fSilent = FALSE;
|
|
BOOL fRegisterAsBrowser = FALSE;
|
|
BOOL fRegisterAsDropTgt = FALSE;
|
|
BOOL fUpdateBrowserReadyState = TRUE;
|
|
VARIANT_BOOL fAmbient;
|
|
|
|
// It is illegal to call ::Load or ::InitNew more than once
|
|
if (_fInit)
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "shv IPersistPropertyBag::Load called when ALREADY INITIALIZED!");
|
|
ASSERT(FALSE);
|
|
return E_FAIL;
|
|
}
|
|
|
|
_InitDefault();
|
|
|
|
// grab all our DWORD-sized (VT_UI4) properties
|
|
struct {
|
|
LPOLESTR pName;
|
|
DWORD* pdw;
|
|
} rgLoadProps[] = {
|
|
{L"Height", (DWORD *)&_size.cy},
|
|
{L"Width", (DWORD *)&_size.cx},
|
|
{L"ViewMode", (DWORD *)&_fs.ViewMode},
|
|
{L"Offline", (DWORD *)&fOffline},
|
|
{L"Silent", (DWORD *)&fSilent},
|
|
{L"RegisterAsBrowser", (DWORD *)&fRegisterAsBrowser},
|
|
{L"RegisterAsDropTarget", (DWORD *)&fRegisterAsDropTgt}
|
|
};
|
|
|
|
for (int i = 0; i < ARRAYSIZE(rgLoadProps); i++)
|
|
{
|
|
SHPropertyBag_ReadDWORD(pBag, rgLoadProps[i].pName, rgLoadProps[i].pdw);
|
|
}
|
|
|
|
// We let ambients take precedence over what we have persisted
|
|
if (SUPERCLASS::_GetAmbientProperty(DISPID_AMBIENT_OFFLINEIFNOTCONNECTED, VT_BOOL, &fAmbient))
|
|
{
|
|
put_Offline(fAmbient);
|
|
}
|
|
else
|
|
{
|
|
put_Offline(BOOL_TO_VARIANTBOOL(fOffline));
|
|
}
|
|
|
|
if (SUPERCLASS::_GetAmbientProperty(DISPID_AMBIENT_SILENT, VT_BOOL, &fAmbient))
|
|
{
|
|
put_Silent(fAmbient);
|
|
}
|
|
else
|
|
{
|
|
put_Silent(BOOL_TO_VARIANTBOOL(fSilent));
|
|
}
|
|
|
|
// If You use fOffline or fSilent after this, you will have to re-init them according
|
|
// to the returned values of fAmbient in the if statements above
|
|
|
|
put_RegisterAsDropTarget(BOOL_TO_VARIANTBOOL(fRegisterAsDropTgt));
|
|
|
|
_fShouldRegisterAsBrowser = VARIANTBOOL_TO_BOOL(fRegisterAsBrowser);
|
|
|
|
// IE3 saved PIXEL size, IE4 saves HIMETRIC size
|
|
DWORD lVal;
|
|
HRESULT hr = SHPropertyBag_ReadDWORD(pBag, L"ExtentX", &lVal);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_sizeHIM.cx = lVal;
|
|
hr = SHPropertyBag_ReadDWORD(pBag, L"ExtentY", &lVal);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_sizeHIM.cy = lVal;
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// convert IE3 info to HIMETRIC
|
|
_sizeHIM = _size;
|
|
PixelsToMetric(&_sizeHIM);
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
for (i = 0; i < ARRAYSIZE(g_boolprops); i++)
|
|
{
|
|
if (SHPropertyBag_ReadBOOLDefRet(pBag, g_boolprops[i].pName, FALSE))
|
|
_fs.fFlags |= g_boolprops[i].flag;
|
|
else
|
|
_fs.fFlags &= ~g_boolprops[i].flag;
|
|
}
|
|
|
|
// grab special properties
|
|
|
|
if (_psb) // if no _psb then container ignored OLEMISC_SETCLIENTSITEFIRST
|
|
{
|
|
if (SUCCEEDED(SHPropertyBag_ReadGUID(pBag, L"ViewID", &_psb->_fldBase._fld._vidRestore)))
|
|
{
|
|
// we sucessfully read the ViewID, so this is a cache hit
|
|
_psb->_fldBase._fld._dwViewPriority = VIEW_PRIORITY_CACHEHIT;
|
|
}
|
|
|
|
_psb->_fldBase._fld._fs = _fs;
|
|
|
|
BSTR bstrVal;
|
|
if (SUCCEEDED(SHPropertyBag_ReadBSTR(pBag, L"Location", &bstrVal)))
|
|
{
|
|
ASSERT(FALSE == _psb->_fAsyncNavigate);
|
|
|
|
hr = WrapSpecialUrl(&bstrVal);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_psb->_fAsyncNavigate = TRUE;
|
|
|
|
if (FAILED(Navigate(bstrVal, NULL, NULL, NULL, NULL)))
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "Load PropertyBag Navigate FAILED!");
|
|
}
|
|
else
|
|
{
|
|
// Navigate is successful (at least initially), let it update ReadyState
|
|
//
|
|
fUpdateBrowserReadyState = FALSE;
|
|
}
|
|
_psb->_fAsyncNavigate = FALSE;
|
|
}
|
|
SysFreeString(bstrVal);
|
|
}
|
|
}
|
|
|
|
_OnLoaded(fUpdateBrowserReadyState);
|
|
|
|
return hr;
|
|
}
|
|
HRESULT CWebBrowserOC::Save(IPropertyBag *pBag, BOOL fClearDirty, BOOL fSaveAllProperties)
|
|
{
|
|
IS_INITIALIZED;
|
|
|
|
HRESULT hres;
|
|
VARIANT var;
|
|
int i;
|
|
SHELLVIEWID vid;
|
|
BOOL bGotView = FALSE;
|
|
|
|
VARIANT_BOOL f;
|
|
BOOL fOffline;
|
|
BOOL fSilent;
|
|
BOOL fRegisterAsDropTgt;
|
|
BOOL fRegisterAsBrowser;
|
|
|
|
get_Offline(&f);
|
|
fOffline = f ? TRUE : FALSE;
|
|
get_Silent(&f);
|
|
fSilent = f ? TRUE : FALSE;
|
|
get_RegisterAsDropTarget(&f);
|
|
fRegisterAsDropTgt = f ? TRUE : FALSE;
|
|
fRegisterAsBrowser = _fShouldRegisterAsBrowser ? TRUE : FALSE;
|
|
|
|
// our state may have changed
|
|
bGotView = _GetViewInfo(&vid);
|
|
|
|
// save all our DWORD-sized properties
|
|
struct {
|
|
LPOLESTR pName;
|
|
DWORD* pdw;
|
|
} rgLoadProps[] = {
|
|
{L"ExtentX", (DWORD *)&_sizeHIM.cx},
|
|
{L"ExtentY", (DWORD *)&_sizeHIM.cy},
|
|
{L"ViewMode", (DWORD *)&_fs.ViewMode},
|
|
{L"Offline", (DWORD *)&fOffline},
|
|
{L"Silent", (DWORD *)&fSilent},
|
|
{L"RegisterAsBrowser", (DWORD *)&fRegisterAsBrowser},
|
|
{L"RegisterAsDropTarget", (DWORD *)&fRegisterAsDropTgt},
|
|
|
|
// IE3 OC stuff here
|
|
{L"Height", (DWORD *)&_size.cy},
|
|
{L"Width", (DWORD *)&_size.cx}
|
|
};
|
|
VariantInit(&var);
|
|
var.vt = VT_I4; // VB doesn't understand VT_UI4! (pBag->Write succeeds,
|
|
// but it doesn't write anything! The load then fails!)
|
|
int nCount = ARRAYSIZE(rgLoadProps);
|
|
if (_pObjectInfo->lVersion != VERSION_1)
|
|
nCount -= 2;
|
|
|
|
for (i = 0; i < nCount; i++)
|
|
{
|
|
var.lVal = *rgLoadProps[i].pdw;
|
|
hres = pBag->Write(rgLoadProps[i].pName, &var);
|
|
if (FAILED(hres))
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "Save PropertyBag could not save %ws for DWORD", rgLoadProps[i].pName);
|
|
return hres;
|
|
}
|
|
}
|
|
|
|
// save all our _fs.fFlags (VT_BOOL) flags
|
|
var.vt = VT_BOOL;
|
|
for (i = 0; i < ARRAYSIZE(g_boolprops); i++)
|
|
{
|
|
var.boolVal = BOOL_TO_VARIANTBOOL(_fs.fFlags & g_boolprops[i].flag);
|
|
hres = pBag->Write(g_boolprops[i].pName, &var);
|
|
if (FAILED(hres))
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "Load PropertyBag did not save %ws for BOOL", g_boolprops[i].pName);
|
|
}
|
|
}
|
|
|
|
// save special properties
|
|
|
|
if (bGotView)
|
|
{
|
|
SHPropertyBag_WriteGUID(pBag, L"ViewID", &(GUID)vid);
|
|
}
|
|
|
|
var.vt = VT_BSTR;
|
|
if (SUCCEEDED(get_LocationURL(&var.bstrVal)))
|
|
{
|
|
hres = pBag->Write(L"Location", &var);
|
|
|
|
VariantClear(&var);
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "Save PropertyBag could not save Location");
|
|
return hres;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var.vt = VT_EMPTY;
|
|
TraceMsg(TF_SHDCONTROL, "Save PropertyBag get_Location FAILED!");
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
// IPersistString
|
|
|
|
STDMETHODIMP CWebBrowserOC::Initialize(LPCWSTR pwszInit)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
BSTR bstr = SysAllocString(pwszInit);
|
|
if (bstr)
|
|
{
|
|
hr = Navigate(bstr, NULL, NULL, NULL, NULL);
|
|
SysFreeString(bstr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
#define THISCLASS CWebBrowserOC
|
|
HRESULT CWebBrowserOC::v_InternalQueryInterface(REFIID riid, void ** ppvObj)
|
|
{
|
|
static const QITAB qit[] = {
|
|
QITABENT(THISCLASS, IWebBrowser2),
|
|
QITABENTMULTI(THISCLASS, IDispatch, IWebBrowser2), // VBA QI's IDispatch and assumes it gets the "default" automation interface, which is IWebBrowser2
|
|
QITABENTMULTI(THISCLASS, IWebBrowser, IWebBrowser2),
|
|
QITABENTMULTI(THISCLASS, IWebBrowserApp, IWebBrowser2),
|
|
QITABENT(THISCLASS, IPersistString),
|
|
QITABENT(THISCLASS, IOleCommandTarget),
|
|
QITABENT(THISCLASS, IObjectSafety),
|
|
QITABENT(THISCLASS, ITargetEmbedding),
|
|
QITABENT(THISCLASS, IExpDispSupport),
|
|
QITABENT(THISCLASS, IExpDispSupportOC),
|
|
QITABENT(THISCLASS, IPersistHistory),
|
|
QITABENT(THISCLASS, IPersistStorage),
|
|
{ 0 },
|
|
};
|
|
HRESULT hres = QISearch(this, qit, riid, ppvObj);
|
|
if (FAILED(hres))
|
|
{
|
|
hres = SUPERCLASS::v_InternalQueryInterface(riid, ppvObj);
|
|
|
|
// we want to expose our aggregated CIEFrameAuto's interfaces
|
|
// in addition to ours.
|
|
if (FAILED(hres))
|
|
{
|
|
hres = _pauto->QueryInterface(riid, ppvObj);
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
// *** IOleInPlaceActiveObject ***
|
|
HRESULT CWebBrowserOC::OnFrameWindowActivate(BOOL fActivate)
|
|
{
|
|
if (_psb)
|
|
_psb->OnFrameWindowActivateBS(fActivate);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::TranslateAccelerator(LPMSG lpMsg)
|
|
{
|
|
if (_psb)
|
|
{
|
|
// FEATURE REVIEW: what wID should we really pass? Is 0 ok?
|
|
if (S_OK == _psb->_TranslateAccelerator(lpMsg, 0, DIRECTION_FORWARD_TO_CHILD))
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
IOIPAMSG(TEXT("TranslateAccelerator cannot forward to _psb"));
|
|
}
|
|
|
|
// SUPERCLASS has no accelerators
|
|
return S_FALSE;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::EnableModeless(BOOL fEnable)
|
|
{
|
|
SUPERCLASS::EnableModeless(fEnable);
|
|
if (_psb)
|
|
{
|
|
return _psb->_EnableModeless(fEnable, DIRECTION_FORWARD_TO_CHILD);
|
|
}
|
|
else
|
|
{
|
|
IOIPAMSG(TEXT("EnableModeless cannot forward to _psb"));
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT CWebBrowserOC::_OnActivateChange(IOleClientSite* pActiveSite, UINT uState)
|
|
{
|
|
HRESULT hres = SUPERCLASS::_OnActivateChange(pActiveSite, uState);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
UINT uViewState;
|
|
|
|
switch (uState)
|
|
{
|
|
case OC_DEACTIVE: uViewState = SVUIA_DEACTIVATE; break;
|
|
case OC_INPLACEACTIVE: uViewState = SVUIA_INPLACEACTIVATE; break;
|
|
case OC_UIACTIVE: uViewState = SVUIA_ACTIVATE_FOCUS; break;
|
|
default: ASSERT(FALSE); return E_INVALIDARG;
|
|
}
|
|
|
|
if (_psb)
|
|
_psb->_UIActivateView(uViewState);
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "shv _OnActivateChange failed, _psb=0x%x", _psb);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
void CWebBrowserOC::_OnInPlaceActivate(void)
|
|
{
|
|
HWND hwnd = NULL;
|
|
|
|
SUPERCLASS::_OnInPlaceActivate();
|
|
|
|
_RegisterWindow();
|
|
|
|
if (_pipsite)
|
|
{
|
|
|
|
// we have to hold on to the target frame until we deactivate,
|
|
// because the psbFrame will delete this thing when it shuts down
|
|
// *before* we are actually deactivated, leaking the unadvise
|
|
// in ieframeauto.
|
|
ASSERT(NULL==_pTargetFramePriv);
|
|
if (SUCCEEDED(IUnknown_QueryService(_pipsite, IID_ITargetFrame2, IID_PPV_ARG(ITargetFramePriv, &_pTargetFramePriv))))
|
|
{
|
|
_pTargetFramePriv->OnChildFrameActivate(SAFECAST(this, IConnectionPointContainer* ));
|
|
}
|
|
|
|
ASSERT(NULL==_pctContainer);
|
|
if (FAILED(_pipsite->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &_pctContainer))))
|
|
{
|
|
// NT 305187 discover.exe crash on exit when _pcli is NULL
|
|
if (_pcli)
|
|
{
|
|
// APPCOMPAT: It should be on IOleInPlaceSite,
|
|
// but MSHTML currently has it on IOleContainer.
|
|
IOleContainer *pCont;
|
|
if (SUCCEEDED(_pcli->GetContainer(&pCont)))
|
|
{
|
|
pCont->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &_pctContainer));
|
|
pCont->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_pipframe && SUCCEEDED(_pipframe->GetWindow(&hwnd)))
|
|
{
|
|
// Check to see if our inplace frame is VB5. If so, we have to hack around
|
|
// _pipframe->EnableModeless calls
|
|
//
|
|
const TCHAR VBM_THUNDER[] = TEXT("Thunder");
|
|
TCHAR strBuf[VB_CLASSNAME_LENGTH];
|
|
|
|
// Check to see if the inplace frame we just called is VB5's forms engine.
|
|
//
|
|
ZeroMemory(strBuf, ARRAYSIZE(strBuf)); // Clear the buffer
|
|
GetClassName(hwnd, strBuf, (VB_CLASSNAME_LENGTH - 1)); // Get the class name of the window.
|
|
if (StrCmpN(strBuf, VBM_THUNDER, (sizeof(VBM_THUNDER)/sizeof(TCHAR))-1) == 0) // Is the first part "Thunder"?
|
|
{
|
|
_fHostedInVB5 = TRUE;
|
|
}
|
|
}
|
|
|
|
{
|
|
//
|
|
// App compat: Check for imagineer technical
|
|
//
|
|
|
|
const WCHAR STR_IMAGINEER[] = L"imagine.exe";
|
|
WCHAR szBuff[MAX_PATH];
|
|
|
|
if (GetModuleFileName(NULL, szBuff, ARRAYSIZE(szBuff)))
|
|
{
|
|
LPWSTR pszFile = PathFindFileName(szBuff);
|
|
|
|
if (pszFile)
|
|
{
|
|
_fHostedInImagineer = (0 == StrNCmpI(pszFile, STR_IMAGINEER,
|
|
ARRAYSIZE(STR_IMAGINEER) - 1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IOIPAMSG(TEXT("_OnInPlaceActivate doesn't have pipsite!"));
|
|
}
|
|
}
|
|
|
|
void CWebBrowserOC::_OnInPlaceDeactivate(void)
|
|
{
|
|
_UnregisterWindow();
|
|
|
|
if (_pTargetFramePriv)
|
|
{
|
|
_pTargetFramePriv->OnChildFrameDeactivate(SAFECAST(this, IConnectionPointContainer*));
|
|
ATOMICRELEASE(_pTargetFramePriv);
|
|
}
|
|
|
|
ATOMICRELEASE(_pctContainer);
|
|
|
|
SUPERCLASS::_OnInPlaceDeactivate();
|
|
}
|
|
|
|
|
|
/*
|
|
** Ambient properties we care about
|
|
*/
|
|
|
|
// We forward IOleControl calls to the docobj.
|
|
// This helper function returns the docobj's IOleControl interface.
|
|
//
|
|
// NOTE: we may want to fail this when the WebBrowserOC was created
|
|
// using IE3's classid just to be safe...
|
|
//
|
|
IOleControl* GetForwardingIOC(IWebBrowser* pwb)
|
|
{
|
|
IOleControl* poc = NULL;
|
|
IDispatch* pdisp;
|
|
|
|
if (SUCCEEDED(pwb->get_Document(&pdisp)))
|
|
{
|
|
pdisp->QueryInterface(IID_PPV_ARG(IOleControl, &poc));
|
|
|
|
pdisp->Release();
|
|
}
|
|
|
|
return poc;
|
|
}
|
|
STDMETHODIMP CWebBrowserOC::GetControlInfo(LPCONTROLINFO pCI)
|
|
{
|
|
HRESULT hres = E_NOTIMPL;
|
|
|
|
// REVIEW: What if we return some docobjects CONTROLINFO here and
|
|
// we navigate somewhere else. Do we have to know when this
|
|
// happens and tell our container that the CONTROLINFO has
|
|
// changed??
|
|
|
|
IOleControl* poc = GetForwardingIOC(_pautoWB2);
|
|
if (poc)
|
|
{
|
|
hres = poc->GetControlInfo(pCI);
|
|
poc->Release();
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
STDMETHODIMP CWebBrowserOC::OnMnemonic(LPMSG pMsg)
|
|
{
|
|
HRESULT hres = E_NOTIMPL;
|
|
|
|
IOleControl* poc = GetForwardingIOC(_pautoWB2);
|
|
if (poc)
|
|
{
|
|
hres = poc->OnMnemonic(pMsg);
|
|
poc->Release();
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
HRESULT __stdcall CWebBrowserOC::OnAmbientPropertyChange(DISPID dispid)
|
|
{
|
|
IS_INITIALIZED;
|
|
|
|
// First let our base class know about the change
|
|
//
|
|
SUPERCLASS::OnAmbientPropertyChange(dispid);
|
|
|
|
// Forward ambient property changes down to the docobject
|
|
// if it is something other than offline or silent
|
|
// for offline and silent, we call the methods to set
|
|
// the properties so that we remember it and these
|
|
// methods forward downwards on their own and so we we
|
|
// end up forwarding twice.
|
|
|
|
if((dispid == DISPID_AMBIENT_OFFLINEIFNOTCONNECTED) || (dispid == DISPID_AMBIENT_SILENT))
|
|
{
|
|
VARIANT_BOOL fAmbient;
|
|
if (SUPERCLASS::_GetAmbientProperty(dispid, VT_BOOL, &fAmbient))
|
|
{
|
|
if (dispid == DISPID_AMBIENT_OFFLINEIFNOTCONNECTED)
|
|
{
|
|
put_Offline(fAmbient);
|
|
}
|
|
else if(dispid == DISPID_AMBIENT_SILENT)
|
|
{
|
|
put_Silent(fAmbient);
|
|
}
|
|
}
|
|
// return ; // BharatS 01/20/97
|
|
// APPCOMPAT --- This could be avoided if the forwarding
|
|
// from simply calling put_offline worked fine but it does not
|
|
// and so the second forwarding can be removed when that is fixed
|
|
|
|
|
|
}
|
|
IOleControl* poc = GetForwardingIOC(_pautoWB2);
|
|
if (poc)
|
|
{
|
|
poc->OnAmbientPropertyChange(dispid);
|
|
poc->Release();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
STDMETHODIMP CWebBrowserOC::FreezeEvents(BOOL bFreeze)
|
|
{
|
|
// First let our base class know about the change
|
|
//
|
|
SUPERCLASS::FreezeEvents(bFreeze);
|
|
|
|
// Forward this down to the docobject
|
|
//
|
|
IOleControl* poc = GetForwardingIOC(_pautoWB2);
|
|
|
|
// delegate only if the freezeevents count is balanced when
|
|
// you receive a FALSE. There may be FALSE calls coming in,
|
|
// before we get a chance to delegate the pending freezeevents calls
|
|
// TRUE is always delegated.
|
|
if (poc && (bFreeze || (_cPendingFreezeEvents == 0)))
|
|
{
|
|
poc->FreezeEvents(bFreeze);
|
|
}
|
|
else
|
|
{
|
|
// keeping a total number of FreezeEvents(TRUE) calls
|
|
// that we have to make up for.
|
|
if ( bFreeze )
|
|
{
|
|
_cPendingFreezeEvents++;
|
|
}
|
|
else
|
|
{
|
|
// Don't let this go negative, otherwise we'll send 4 billion FreezeEvents(TRUE)
|
|
// to the DocObject in CWebBrowserOC::_OnSetShellView. (QFE [alanau])(ferhane)
|
|
if (EVAL(_cPendingFreezeEvents > 0))
|
|
{
|
|
_cPendingFreezeEvents --;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (poc)
|
|
poc->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// CWebBrowserSB just started viewing psvNew - do our OC stuff now
|
|
//
|
|
void CWebBrowserOC::_OnSetShellView(IShellView* psvNew)
|
|
{
|
|
_fDirty = TRUE;
|
|
// NOTE: Document, Type, LocationName, LocationURL, Busy just changed...
|
|
// PropertyChanged(DISPID_LOCATION);
|
|
// NOTE: that is the job of the CBaseBrowser to tell us really.
|
|
// ideally we would not put this here at all (or in _OnReleaseShellV...
|
|
_SendAdvise(OBJECTCODE_DATACHANGED); // implies OBJECTCODE_VIEWCHANGED
|
|
|
|
// we might have received FreezeEvents(TRUE) calls from the container
|
|
// and if the document was not ready, we might not have had a chance
|
|
// to pass them down the stream. This is the time to make up for it.
|
|
|
|
if (_cPendingFreezeEvents > 0)
|
|
{
|
|
IOleControl* poc = GetForwardingIOC(_pautoWB2);
|
|
|
|
if (poc)
|
|
{
|
|
for ( ; _cPendingFreezeEvents > 0; _cPendingFreezeEvents-- )
|
|
{
|
|
// Forward this down to the docobject
|
|
poc->FreezeEvents(TRUE);
|
|
}
|
|
|
|
poc->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
// CWebBrowserSB is releasing the currently viewed IShellView
|
|
void CWebBrowserOC::_OnReleaseShellView()
|
|
{
|
|
}
|
|
|
|
|
|
// *** IOleCommandTarget
|
|
//
|
|
// our version simply forwards to the object below our CWebBrowserSB
|
|
//
|
|
HRESULT CWebBrowserOC::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
|
|
{
|
|
if (_psb && _psb->_bbd._pctView)
|
|
return _psb->_bbd._pctView->QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
|
|
|
|
return OLECMDERR_E_UNKNOWNGROUP;
|
|
}
|
|
HRESULT CWebBrowserOC::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
|
|
{
|
|
HRESULT hr = OLECMDERR_E_UNKNOWNGROUP;
|
|
if (_psb)
|
|
{
|
|
if (pguidCmdGroup==NULL)
|
|
{
|
|
switch(nCmdID)
|
|
{
|
|
case OLECMDID_STOP:
|
|
{
|
|
LPITEMIDLIST pidlIntended = (_psb->_bbd._pidlPending) ? ILClone(_psb->_bbd._pidlPending) : NULL;
|
|
_psb->_CancelPendingNavigation();
|
|
|
|
// We've just canceled the pending navigation. We may not have a current page! The following
|
|
// accomplishes two goals:
|
|
//
|
|
// 1. Gives the user some information about the frame that couldn't navigate.
|
|
// 2. Allows the browser to reach READYSTATE_COMPLETE
|
|
//
|
|
if (!_psb->_bbd._pidlCur)
|
|
{
|
|
// We display the navcancl.htm page in most cases.
|
|
// However, we won't display it if the call has
|
|
// explicitly specified that we shouldn't.
|
|
//
|
|
if ( !pvarargIn
|
|
|| V_VT(pvarargIn) != VT_BOOL
|
|
|| V_BOOL(pvarargIn) == VARIANT_TRUE)
|
|
{
|
|
TCHAR szResURL[MAX_URL_STRING];
|
|
|
|
hr = MLBuildResURLWrap(TEXT("shdoclc.dll"),
|
|
HINST_THISDLL,
|
|
ML_CROSSCODEPAGE,
|
|
TEXT("navcancl.htm"),
|
|
szResURL,
|
|
ARRAYSIZE(szResURL),
|
|
TEXT("shdocvw.dll"));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_psb->_ShowBlankPage(szResURL, pidlIntended);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pidlIntended)
|
|
ILFree(pidlIntended);
|
|
break; // Note that we need to fall through.
|
|
}
|
|
|
|
case OLECMDID_ENABLE_INTERACTION:
|
|
if (pvarargIn && pvarargIn->vt == VT_I4)
|
|
{
|
|
_psb->_fPausedByParent = BOOLIFY(pvarargIn->lVal);
|
|
}
|
|
break; // Note that we need to fall through.
|
|
}
|
|
|
|
hr = S_OK;
|
|
// WARNING: fall through to forward down
|
|
}
|
|
if (_psb->_bbd._pctView)
|
|
hr = _psb->_bbd._pctView->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// We hit this code if the normal IOleCommandTarget chain is broken (such as
|
|
// browser band in the browser bar). In this case, we get the command target
|
|
// to the top level browser and send OLECMDID_SETDOWNLOADSTATE to it.
|
|
//
|
|
// Returns:
|
|
// S_OK If we found the top level browser and it processed it.
|
|
// hresRet Otherwise
|
|
//
|
|
HRESULT CWebBrowserOC::_SetDownloadState(HRESULT hresRet, DWORD nCmdexecopt, VARIANTARG *pvarargIn)
|
|
{
|
|
ASSERT(hresRet == OLECMDERR_E_UNKNOWNGROUP || hresRet == OLECMDERR_E_NOTSUPPORTED);
|
|
|
|
IOleCommandTarget* pcmdtTop;
|
|
if (_psb && SUCCEEDED(_psb->_QueryServiceParent(SID_STopLevelBrowser, IID_PPV_ARG(IOleCommandTarget, &pcmdtTop))))
|
|
{
|
|
ASSERT(pcmdtTop != _psb);
|
|
VARIANTARG var;
|
|
if (pvarargIn && pvarargIn->lVal)
|
|
{
|
|
ASSERT(pvarargIn->vt == VT_I4 || pvarargIn->vt == VT_BOOL || pvarargIn->vt == VT_UNKNOWN);
|
|
//
|
|
// Notice that we pass the pointer to this OC so that the top
|
|
// level browser can keep track of it. This is a new behavior
|
|
// which is different from IE 3.0.
|
|
//
|
|
var.vt = VT_UNKNOWN;
|
|
var.punkVal = SAFECAST(this, IOleCommandTarget*);
|
|
}
|
|
else
|
|
{
|
|
var.vt = VT_BOOL;
|
|
var.lVal = FALSE;
|
|
}
|
|
HRESULT hresT = pcmdtTop->Exec(NULL, OLECMDID_SETDOWNLOADSTATE, nCmdexecopt, &var, NULL);
|
|
|
|
TraceMsg(DM_FORSEARCHBAND, "WBOC::_SetDownloadState pcmdTop->Exec returned %x", hresT);
|
|
|
|
if (SUCCEEDED(hresT))
|
|
{
|
|
hresRet = S_OK;
|
|
}
|
|
pcmdtTop->Release();
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(DM_FORSEARCHBAND, "WBOC::_SetDownloadState can't find the top guy");
|
|
}
|
|
|
|
return hresRet;
|
|
}
|
|
|
|
#ifdef FEATURE_FRAMES
|
|
|
|
// *** ITargetEmedding ***
|
|
|
|
HRESULT CWebBrowserOC::GetTargetFrame(ITargetFrame **ppTargetFrame)
|
|
{
|
|
if (_psb)
|
|
{
|
|
return _psb->QueryServiceItsOwn(IID_ITargetFrame2, IID_PPV_ARG(ITargetFrame, ppTargetFrame));
|
|
}
|
|
else
|
|
{
|
|
*ppTargetFrame = NULL;
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
// *** CImpIConnectionPoint override ***
|
|
CConnectionPoint* CWebBrowserOC::_FindCConnectionPointNoRef(BOOL fdisp, REFIID iid)
|
|
{
|
|
CConnectionPoint *pccp;
|
|
|
|
// Warning: Some apps (MSDN for one) passes in IID_IDispatch and
|
|
// expect the ole events. So we need to be careful on which one we return.
|
|
//
|
|
if (fdisp && IsEqualIID(iid, IID_IDispatch))
|
|
{
|
|
if (_pObjectInfo->lVersion == VERSION_1)
|
|
pccp = &m_cpWB1Events;
|
|
else
|
|
pccp = &m_cpEvents;
|
|
}
|
|
|
|
else if (IsEqualIID(iid, DIID_DWebBrowserEvents2))
|
|
{
|
|
pccp = &m_cpEvents;
|
|
}
|
|
else if (IsEqualIID(iid, DIID_DWebBrowserEvents))
|
|
{
|
|
pccp = &m_cpWB1Events;
|
|
}
|
|
else if (IsEqualIID(iid, IID_IPropertyNotifySink))
|
|
{
|
|
pccp = &m_cpPropNotify;
|
|
}
|
|
else
|
|
{
|
|
pccp = NULL;
|
|
}
|
|
|
|
return pccp;
|
|
}
|
|
|
|
STDMETHODIMP CWebBrowserOC::EnumConnectionPoints(LPENUMCONNECTIONPOINTS * ppEnum)
|
|
{
|
|
return CreateInstance_IEnumConnectionPoints(ppEnum, 3,
|
|
m_cpEvents.CastToIConnectionPoint(),
|
|
m_cpWB1Events.CastToIConnectionPoint(),
|
|
m_cpPropNotify.CastToIConnectionPoint());
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** Properties and Methods we implement
|
|
*/
|
|
|
|
// Invoke perf
|
|
//
|
|
HRESULT CWebBrowserOC::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
|
|
// we should probably check that riid is IID_NULL...
|
|
|
|
_fInsideInvokeCall = TRUE; // we're inside an invoke
|
|
|
|
switch (dispidMember)
|
|
{
|
|
// handle ReadyState immediately for performance (avoid oleaut a tad longer)...
|
|
case DISPID_READYSTATE:
|
|
ASSERT(pdispparams && pdispparams->cArgs==0);
|
|
if (EVAL(pvarResult) && (wFlags & DISPATCH_PROPERTYGET))
|
|
{
|
|
ZeroMemory(pvarResult, SIZEOF(*pvarResult));
|
|
pvarResult->vt = VT_I4;
|
|
hres = get_ReadyState((READYSTATE*)(&pvarResult->lVal));
|
|
goto Cleanup;
|
|
}
|
|
break; // let the below invoke call give us the proper error value
|
|
|
|
// forward these two down to our embedded object so that
|
|
// Trident can handle cross-frame security correctly
|
|
case DISPID_SECURITYCTX:
|
|
case DISPID_SECURITYDOMAIN:
|
|
{
|
|
IDispatch* pdisp;
|
|
if (SUCCEEDED(_pautoWB2->get_Document(&pdisp)))
|
|
{
|
|
hres = pdisp->Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
|
|
pdisp->Release();
|
|
goto Cleanup;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// handle the default after the switch.
|
|
break;
|
|
}
|
|
|
|
hres = CShellOcx::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
|
|
|
|
Cleanup:
|
|
|
|
_fInsideInvokeCall = FALSE; // We are leaving the invoke
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
// IObjectSafety override so script can't talk to us from an unsafe zone
|
|
HRESULT CWebBrowserOC::SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions)
|
|
{
|
|
HRESULT hr = CObjectSafety::SetInterfaceSafetyOptions(riid, dwOptionSetMask, dwEnabledOptions);
|
|
|
|
// If we are hosted in IEXPLORER.EXE or EXPLORER.EXE (eventually this should be the default, but we need longer app-compat simmer time)
|
|
// And we can get a URL from our parent
|
|
// And the policy for that URL is "disable WebOC script access" (default for internet zone)
|
|
if (GetModuleHandle(TEXT("EXPLORER.EXE")) || GetModuleHandle(TEXT("IEXPLORE.EXE")))
|
|
{
|
|
IHTMLDocument2 *pHtmlDoc;
|
|
if (SUCCEEDED(GetHTMLDoc2(_pcli, &pHtmlDoc))) // if the parent isn't trident, then we must be client-side code hosting weboc directly - no need to bail
|
|
{
|
|
BSTR bstrURL;
|
|
if (SUCCEEDED(pHtmlDoc->get_URL(&bstrURL)))
|
|
{
|
|
DWORD dwPolicy = 0;
|
|
DWORD dwContext = 0;
|
|
|
|
ZoneCheckUrlEx(bstrURL, &dwPolicy, sizeof(dwPolicy), &dwContext, sizeof(dwContext),
|
|
URLACTION_ACTIVEX_NO_WEBOC_SCRIPT, 0, NULL);
|
|
|
|
if (GetUrlPolicyPermissions(dwPolicy) != URLPOLICY_ALLOW)
|
|
{
|
|
// Then we don't support script access - override whatever we were told above.
|
|
hr = E_ACCESSDENIED;
|
|
}
|
|
|
|
SysFreeString(bstrURL);
|
|
}
|
|
pHtmlDoc->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// Wrap around iedisp
|
|
//
|
|
|
|
#define WRAP_WB2(fn, args, nargs) \
|
|
HRESULT CWebBrowserOC :: fn args { return _pautoWB2-> fn nargs; }
|
|
#define WRAP_WB2_DESIGN(fn, args, nargs) \
|
|
HRESULT CWebBrowserOC :: fn args { if (_IsDesignMode()) return E_FAIL; else return _pautoWB2-> fn nargs; }
|
|
|
|
// IWebBrowser methods
|
|
//
|
|
WRAP_WB2_DESIGN(GoBack, (), ())
|
|
WRAP_WB2_DESIGN(GoForward, (), ())
|
|
WRAP_WB2_DESIGN(GoHome, (), ())
|
|
WRAP_WB2_DESIGN(GoSearch, (), ())
|
|
WRAP_WB2_DESIGN(Refresh, (), ())
|
|
WRAP_WB2_DESIGN(Refresh2, (VARIANT * Level), (Level))
|
|
WRAP_WB2_DESIGN(Stop, (), ())
|
|
WRAP_WB2(get_Type, (BSTR * pbstrType), (pbstrType))
|
|
WRAP_WB2(get_LocationName, (BSTR * pbstrLocationName), (pbstrLocationName))
|
|
WRAP_WB2(get_LocationURL, (BSTR * pbstrLocationURL), (pbstrLocationURL))
|
|
WRAP_WB2(get_Busy, (VARIANT_BOOL * pBool), (pBool))
|
|
|
|
HRESULT CWebBrowserOC::Navigate(BSTR URL,
|
|
VARIANT * Flags,
|
|
VARIANT * TargetFrameName,
|
|
VARIANT * PostData,
|
|
VARIANT * Headers)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (_dwSafetyOptions)
|
|
{
|
|
hr = WrapSpecialUrl(&URL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (!AccessAllowedToNamedFrame(TargetFrameName))
|
|
hr = E_ACCESSDENIED;
|
|
else
|
|
hr = _pautoWB2->Navigate(URL, Flags, TargetFrameName, PostData, Headers);
|
|
}
|
|
}
|
|
else
|
|
hr = _pautoWB2->Navigate(URL, Flags, TargetFrameName, PostData, Headers);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::get_Application(IDispatch **ppDisp)
|
|
{
|
|
PROPMSG(TEXT("get_Application"));
|
|
return QueryInterface(IID_PPV_ARG(IDispatch, ppDisp));
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::get_Parent(IDispatch **ppDisp)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
PROPMSG(TEXT("get_Parent"));
|
|
|
|
if (ppDisp)
|
|
*ppDisp = NULL;
|
|
|
|
if (_pcli)
|
|
{
|
|
IOleContainer* pContainer;
|
|
|
|
hres = _pcli->GetContainer(&pContainer);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = pContainer->QueryInterface(IID_PPV_ARG(IDispatch, ppDisp));
|
|
|
|
if (SUCCEEDED(hres) && _dwSafetyOptions)
|
|
hres = MakeSafeForScripting((IUnknown**)ppDisp);
|
|
|
|
pContainer->Release();
|
|
}
|
|
else
|
|
{
|
|
PROPMSG(TEXT("get_Parent couldn't find the container!"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PROPMSG(TEXT("get_Parent does not have _pcli!"));
|
|
}
|
|
|
|
// if there was an error *ppDisop is NULL, and so VB realizes
|
|
// this is a "nothing" dispatch -- returning failure causes
|
|
// error boxes to appear. ugh.
|
|
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::get_Container(IDispatch **ppDisp)
|
|
{
|
|
// Container property is "same as parent" unless there is no parent.
|
|
// Since we always have a parent, let get_Parent handle this.
|
|
PROPMSG(TEXT("get_Containter passing off to get_Parent"));
|
|
return get_Parent(ppDisp);
|
|
}
|
|
HRESULT CWebBrowserOC::get_Document(IDispatch **ppDisp)
|
|
{
|
|
HRESULT hres = _pautoWB2->get_Document(ppDisp);
|
|
|
|
if (FAILED(hres) && ppDisp)
|
|
{
|
|
*ppDisp = NULL;
|
|
}
|
|
|
|
if (SUCCEEDED(hres) && _dwSafetyOptions)
|
|
hres = MakeSafeForScripting((IUnknown**)ppDisp);
|
|
|
|
|
|
// if there was an error *ppDisop is NULL, and so VB realizes
|
|
// this is a "nothing" dispatch -- returning failure causes
|
|
// error boxes to appear. ugh.
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::get_TopLevelContainer(VARIANT_BOOL * pBool)
|
|
{
|
|
PROPMSG(TEXT("get_TopLevelContainer"));
|
|
|
|
if (!pBool)
|
|
return E_INVALIDARG;
|
|
|
|
*pBool = FALSE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
void FireEvent_OnSetWindowPos(IUnknown *punkCPContainer, DISPID dispid, long lValue)
|
|
{
|
|
VARIANTARG args[1];
|
|
IUnknown_CPContainerInvokeParam(punkCPContainer, DIID_DWebBrowserEvents2,
|
|
dispid, args, 1, VT_I4, lValue);
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::get_Left(long * pl)
|
|
{
|
|
*pl = _rcPos.left;
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::put_Left(long Left)
|
|
{
|
|
FireEvent_OnSetWindowPos(_pautoEDS, DISPID_WINDOWSETLEFT, Left);
|
|
|
|
if (_pipsite)
|
|
{
|
|
RECT rc = _rcPos;
|
|
rc.left = Left;
|
|
|
|
return _pipsite->OnPosRectChange(&rc);
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "put_Left has no _pipsite to notify!");
|
|
return E_UNEXPECTED;
|
|
}
|
|
}
|
|
HRESULT CWebBrowserOC::get_Top(long * pl)
|
|
{
|
|
*pl = _rcPos.top;
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::put_Top(long Top)
|
|
{
|
|
FireEvent_OnSetWindowPos(_pautoEDS, DISPID_WINDOWSETTOP, Top);
|
|
|
|
if (_pipsite)
|
|
{
|
|
RECT rc = _rcPos;
|
|
rc.top = Top;
|
|
|
|
return(_pipsite->OnPosRectChange(&rc));
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "put_Top has no _pipsite to notify!");
|
|
return(E_UNEXPECTED);
|
|
}
|
|
}
|
|
HRESULT CWebBrowserOC::get_Width(long * pl)
|
|
{
|
|
*pl = _rcPos.right - _rcPos.left;
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::put_Width(long Width)
|
|
{
|
|
FireEvent_OnSetWindowPos(_pautoEDS, DISPID_WINDOWSETWIDTH, Width);
|
|
|
|
if (_pipsite)
|
|
{
|
|
RECT rc = _rcPos;
|
|
rc.right = rc.left + Width;
|
|
|
|
return(_pipsite->OnPosRectChange(&rc));
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "put_Width has no _pipsite to notify!");
|
|
return(E_UNEXPECTED);
|
|
}
|
|
}
|
|
HRESULT CWebBrowserOC::get_Height(long * pl)
|
|
{
|
|
*pl = _rcPos.bottom - _rcPos.top;
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::put_Height(long Height)
|
|
{
|
|
FireEvent_OnSetWindowPos(_pautoEDS, DISPID_WINDOWSETHEIGHT, Height);
|
|
|
|
if (_pipsite)
|
|
{
|
|
RECT rc = _rcPos;
|
|
rc.bottom = rc.top + Height;
|
|
|
|
return(_pipsite->OnPosRectChange(&rc));
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_SHDCONTROL, "put_Height has no _pipsite to notify!");
|
|
return(E_UNEXPECTED);
|
|
}
|
|
}
|
|
|
|
// IWebBrowserApp methods
|
|
//
|
|
WRAP_WB2_DESIGN(PutProperty, (BSTR szProperty, VARIANT vtValue), (szProperty, vtValue))
|
|
WRAP_WB2_DESIGN(GetProperty, (BSTR szProperty, VARIANT * pvtValue), (szProperty, pvtValue))
|
|
WRAP_WB2(get_FullName, (BSTR * pbstrFullName), (pbstrFullName))
|
|
WRAP_WB2(get_Path, (BSTR * pbstrPath), (pbstrPath))
|
|
|
|
HRESULT CWebBrowserOC::Quit()
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
HRESULT CWebBrowserOC::ClientToWindow(int * pcx, int * pcy)
|
|
{
|
|
LONG lX = *pcx, lY = *pcy;
|
|
|
|
VARIANTARG args[2];
|
|
IUnknown_CPContainerInvokeParam(_pautoEDS, DIID_DWebBrowserEvents2,
|
|
DISPID_CLIENTTOHOSTWINDOW, args, 2,
|
|
VT_I4 | VT_BYREF, &lX,
|
|
VT_I4 | VT_BYREF, &lY);
|
|
*pcx = lX;
|
|
*pcy = lY;
|
|
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::get_Name(BSTR * pbstrName)
|
|
{
|
|
*pbstrName = LoadBSTR(IDS_SHELLEXPLORER);
|
|
return *pbstrName ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
HRESULT CWebBrowserOC::get_HWND(LONG_PTR * pHWND)
|
|
{
|
|
*pHWND = NULL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::get_FullScreen(VARIANT_BOOL * pBool)
|
|
{
|
|
*pBool = BOOL_TO_VARIANTBOOL(_fFullScreen);
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::put_FullScreen(VARIANT_BOOL Value)
|
|
{
|
|
_fFullScreen = VARIANTBOOL_TO_BOOL(Value);
|
|
FireEvent_OnAdornment(_pautoEDS, DISPID_ONFULLSCREEN, Value);
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::get_Visible(VARIANT_BOOL * pBool)
|
|
{
|
|
*pBool = BOOL_TO_VARIANTBOOL(_fVisible);
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::put_Visible(VARIANT_BOOL Value)
|
|
{
|
|
_fVisible = VARIANTBOOL_TO_BOOL(Value);
|
|
FireEvent_OnAdornment(_pautoEDS, DISPID_ONVISIBLE, Value);
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::get_StatusBar(VARIANT_BOOL * pBool)
|
|
{
|
|
*pBool = BOOL_TO_VARIANTBOOL(!_fNoStatusBar);
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::put_StatusBar(VARIANT_BOOL Value)
|
|
{
|
|
_fNoStatusBar = !VARIANTBOOL_TO_BOOL(Value);
|
|
FireEvent_OnAdornment(_pautoEDS, DISPID_ONSTATUSBAR, Value);
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::get_StatusText(BSTR * pbstr)
|
|
{
|
|
*pbstr = NULL;
|
|
return E_FAIL;
|
|
}
|
|
HRESULT CWebBrowserOC::put_StatusText(BSTR bstr)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
HRESULT CWebBrowserOC::get_ToolBar(int * pBool)
|
|
{
|
|
// BOGUS: variant values for int type
|
|
*pBool = (!_fNoToolBar) ? VARIANT_TRUE : VARIANT_FALSE;
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::put_ToolBar(int iToolbar)
|
|
{
|
|
_fNoToolBar = (!iToolbar) ? TRUE : FALSE;
|
|
FireEvent_OnAdornment(_pautoEDS, DISPID_ONTOOLBAR, iToolbar);
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::get_MenuBar(VARIANT_BOOL * pvbMenuBar)
|
|
{
|
|
*pvbMenuBar = BOOL_TO_VARIANTBOOL(!_fNoMenuBar);
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::put_MenuBar(VARIANT_BOOL vbMenuBar)
|
|
{
|
|
_fNoMenuBar = !VARIANTBOOL_TO_BOOL(vbMenuBar);
|
|
FireEvent_OnAdornment(_pautoEDS, DISPID_ONMENUBAR, vbMenuBar);
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::get_AddressBar(VARIANT_BOOL * pvbAddressBar)
|
|
{
|
|
*pvbAddressBar = BOOL_TO_VARIANTBOOL(!_fNoAddressBar);
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::put_AddressBar(VARIANT_BOOL vbAddressBar)
|
|
{
|
|
_fNoAddressBar = !VARIANTBOOL_TO_BOOL(vbAddressBar);
|
|
FireEvent_OnAdornment(_pautoEDS, DISPID_ONADDRESSBAR, vbAddressBar);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::put_Resizable(VARIANT_BOOL vbResizable)
|
|
{
|
|
FireEvent_OnAdornment(_pautoEDS, DISPID_WINDOWSETRESIZABLE, vbResizable);
|
|
return S_OK;
|
|
}
|
|
|
|
// IWebBrowser2 methods
|
|
//
|
|
WRAP_WB2_DESIGN(QueryStatusWB, (OLECMDID cmdID, OLECMDF * pcmdf), (cmdID, pcmdf))
|
|
WRAP_WB2_DESIGN(ShowBrowserBar, (VARIANT * pvaClsid, VARIANT * pvaShow, VARIANT * pvaSize), (pvaClsid, pvaShow, pvaSize))
|
|
WRAP_WB2(get_ReadyState, (READYSTATE * plReadyState), (plReadyState))
|
|
WRAP_WB2(get_RegisterAsDropTarget, (VARIANT_BOOL * pbRegister), (pbRegister))
|
|
WRAP_WB2(put_RegisterAsDropTarget, (VARIANT_BOOL bRegister), (bRegister))
|
|
WRAP_WB2(get_Offline, (VARIANT_BOOL * pbOffline), (pbOffline))
|
|
WRAP_WB2(put_Offline, (VARIANT_BOOL bOffline), (bOffline))
|
|
WRAP_WB2(get_Silent, (VARIANT_BOOL * pbSilent), (pbSilent))
|
|
WRAP_WB2(put_Silent, (VARIANT_BOOL bSilent), (bSilent))
|
|
|
|
|
|
HRESULT
|
|
CWebBrowserOC::Navigate2(VARIANT * URL,
|
|
VARIANT * Flags,
|
|
VARIANT * TargetFrameName,
|
|
VARIANT * PostData,
|
|
VARIANT * Headers)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (_dwSafetyOptions && ((WORD)VT_BSTR == URL->vt) && URL->bstrVal)
|
|
{
|
|
hr = WrapSpecialUrl(&URL->bstrVal);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (!AccessAllowedToNamedFrame(TargetFrameName))
|
|
hr = E_ACCESSDENIED;
|
|
else
|
|
hr = _pautoWB2->Navigate2(URL, Flags, TargetFrameName, PostData, Headers);
|
|
}
|
|
}
|
|
else
|
|
hr = _pautoWB2->Navigate2(URL, Flags, TargetFrameName, PostData, Headers);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::ExecWB(OLECMDID cmdID, OLECMDEXECOPT cmdexecopt,
|
|
VARIANT * pvaIn, VARIANT * pvaOut)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if ( !_IsDesignMode() )
|
|
{
|
|
|
|
// do not process print preview commands given from script for security reasons
|
|
// Ferhane IE60 Bug#16693
|
|
// Print templates have extra privelages.
|
|
// Print/Preview allows you to specify a custom print template URL as a BSTR or in a safearray.
|
|
// This is a security hole if available from script. Disallow it.
|
|
if ( _fInsideInvokeCall
|
|
&& ( cmdID == OLECMDID_PRINTPREVIEW
|
|
|| cmdID == OLECMDID_PRINT)
|
|
&& pvaIn
|
|
&& ( V_VT(pvaIn) == VT_BSTR
|
|
|| V_VT(pvaIn) == VT_ARRAY)
|
|
)
|
|
{
|
|
return E_ACCESSDENIED; // More meaningful than E_FAIL
|
|
}
|
|
|
|
// if _dwSafetyOptions are set then we are suppossed to be
|
|
// running in secure mode. This means the UI-less printing should NOT
|
|
// be honored. This is a security issue, see ie bug 23620.
|
|
// otherwise just let the call go through
|
|
if ((cmdID == OLECMDID_PRINT) && _dwSafetyOptions)
|
|
{
|
|
// so if the UI-less- request flag is set we need to unset it.
|
|
if (cmdexecopt == OLECMDEXECOPT_DONTPROMPTUSER)
|
|
cmdexecopt = OLECMDEXECOPT_DODEFAULT;
|
|
}
|
|
|
|
// If the optional argument pvargin is not specified make it VT_EMPTY.
|
|
if (pvaIn && (V_VT(pvaIn) == VT_ERROR) && (V_ERROR(pvaIn) == DISP_E_PARAMNOTFOUND))
|
|
{
|
|
V_VT(pvaIn) = VT_EMPTY;
|
|
V_I4(pvaIn) = 0;
|
|
}
|
|
|
|
// If the optional argument pvargin is not specified make it VT_EMPTY.
|
|
if (pvaOut && (V_VT(pvaOut) == VT_ERROR) && (V_ERROR(pvaOut) == DISP_E_PARAMNOTFOUND))
|
|
{
|
|
V_VT(pvaOut) = VT_EMPTY;
|
|
V_I4(pvaOut) = 0;
|
|
}
|
|
|
|
if ( cmdID == OLECMDID_PASTE
|
|
|| cmdID == OLECMDID_COPY
|
|
|| cmdID == OLECMDID_CUT)
|
|
{
|
|
BSTR bstrUrl;
|
|
|
|
if (_dwSafetyOptions)
|
|
return S_OK;
|
|
|
|
if (SUCCEEDED(get_LocationURL(&bstrUrl)))
|
|
{
|
|
DWORD dwPolicy = 0;
|
|
DWORD dwContext = 0;
|
|
|
|
ZoneCheckUrlEx(bstrUrl, &dwPolicy, SIZEOF(dwPolicy), &dwContext, SIZEOF(dwContext),
|
|
URLACTION_SCRIPT_PASTE, 0, NULL);
|
|
|
|
SysFreeString(bstrUrl);
|
|
|
|
if (GetUrlPolicyPermissions(dwPolicy) != URLPOLICY_ALLOW)
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
// now pass along the call
|
|
hr = _pautoWB2->ExecWB(cmdID, cmdexecopt, pvaIn, pvaOut);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::get_RegisterAsBrowser(VARIANT_BOOL * pbRegister)
|
|
{
|
|
*pbRegister = BOOL_TO_VARIANTBOOL(_fShouldRegisterAsBrowser);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::put_RegisterAsBrowser(VARIANT_BOOL bRegister)
|
|
{
|
|
_fShouldRegisterAsBrowser = VARIANTBOOL_TO_BOOL(bRegister);
|
|
|
|
if (bRegister)
|
|
_RegisterWindow();
|
|
else
|
|
_UnregisterWindow();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::get_TheaterMode(VARIANT_BOOL * pvbTheaterMode)
|
|
{
|
|
*pvbTheaterMode = BOOL_TO_VARIANTBOOL(_fTheaterMode);
|
|
return S_OK;
|
|
}
|
|
HRESULT CWebBrowserOC::put_TheaterMode(VARIANT_BOOL Value)
|
|
{
|
|
_fTheaterMode = VARIANTBOOL_TO_BOOL(Value);
|
|
FireEvent_OnAdornment(_pautoEDS, DISPID_ONTHEATERMODE, Value);
|
|
return S_OK;
|
|
}
|
|
|
|
// IExpDispSupport
|
|
//
|
|
HRESULT CWebBrowserOC::OnTranslateAccelerator(MSG *pMsg,DWORD grfModifiers)
|
|
{
|
|
return IUnknown_TranslateAcceleratorOCS(_pcli, pMsg, grfModifiers);
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::OnInvoke(DISPID dispidMember, REFIID iid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams,
|
|
VARIANT * pVarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
|
|
{
|
|
// We get first crack at this
|
|
HRESULT hres = _pautoEDS->OnInvoke(dispidMember, iid, lcid, wFlags, pdispparams, pVarResult,pexcepinfo,puArgErr);
|
|
|
|
// let the container get second crack at ambient properties
|
|
//
|
|
if (FAILED(hres))
|
|
{
|
|
if (!_pDispAmbient)
|
|
{
|
|
if (_pcli)
|
|
_pcli->QueryInterface(IID_PPV_ARG(IDispatch, &_pDispAmbient));
|
|
}
|
|
if (_pDispAmbient)
|
|
{
|
|
hres = _pDispAmbient->Invoke(dispidMember, iid, lcid, wFlags, pdispparams, pVarResult,pexcepinfo,puArgErr);
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
// IExpDispSupportOC
|
|
//
|
|
HRESULT CWebBrowserOC::OnOnControlInfoChanged()
|
|
{
|
|
HRESULT hres = E_NOTIMPL;
|
|
|
|
if (_pcli)
|
|
{
|
|
IOleControlSite* pocs;
|
|
if (SUCCEEDED(_pcli->QueryInterface(IID_PPV_ARG(IOleControlSite, &pocs))))
|
|
{
|
|
hres = pocs->OnControlInfoChanged();
|
|
pocs->Release();
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
HRESULT CWebBrowserOC::GetDoVerbMSG(MSG *pMsg)
|
|
{
|
|
if (_pmsgDoVerb)
|
|
{
|
|
*pMsg = *_pmsgDoVerb;
|
|
return S_OK;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
HRESULT CWebBrowserOC::LoadHistory(IStream *pstm, IBindCtx *pbc)
|
|
{
|
|
_InitDefault();
|
|
|
|
ASSERT(_psb);
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (_psb)
|
|
{
|
|
hr = _psb->LoadHistory(pstm, pbc);
|
|
|
|
_OnLoaded(FAILED(hr));
|
|
|
|
TraceMsg(TF_TRAVELLOG, "WBOC::LoadHistory pstm = %x, pbc = %x, hr = %x", pstm, pbc, hr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::SaveHistory(IStream *pstm)
|
|
{
|
|
ASSERT(_psb);
|
|
|
|
TraceMsg(TF_TRAVELLOG, "WBOC::SaveHistory calling psb->SaveHistory");
|
|
|
|
return _psb ? _psb->SaveHistory(pstm) : E_FAIL;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::SetPositionCookie(DWORD dw)
|
|
{
|
|
ASSERT(_psb);
|
|
|
|
TraceMsg(TF_TRAVELLOG, "WBOC::SetPositionCookie calling psb->GetPositionCookie");
|
|
return _psb ? _psb->SetPositionCookie(dw) : E_FAIL;
|
|
}
|
|
|
|
HRESULT CWebBrowserOC::GetPositionCookie(DWORD *pdw)
|
|
{
|
|
ASSERT(_psb);
|
|
|
|
TraceMsg(TF_TRAVELLOG, "WBOC::GetPositionCookie calling psb->GetPositionCookie");
|
|
return _psb ? _psb->GetPositionCookie(pdw) : E_FAIL;
|
|
}
|
|
|
|
HMODULE CWebBrowserOC::_GetBrowseUI()
|
|
{
|
|
if (_hBrowseUI == HMODULE_NOTLOADED)
|
|
{
|
|
_hBrowseUI = LoadLibrary(TEXT("browseui.dll"));
|
|
}
|
|
|
|
return _hBrowseUI;
|
|
}
|
|
|
|
BOOL CWebBrowserOC::AccessAllowedToNamedFrame(VARIANT *varTargetFrameName)
|
|
{
|
|
BOOL fAllowed = TRUE;
|
|
HRESULT hr = S_OK;
|
|
ITargetFrame2 * pTopTargetFrame = NULL;
|
|
IUnknown * punkTargetFrame = NULL;
|
|
IWebBrowser2 * pIWB2Target = NULL;
|
|
BSTR bstrTargetUrl = NULL;
|
|
BSTR bstrSrcUrl = NULL;
|
|
|
|
if (varTargetFrameName && ((WORD)VT_BSTR == varTargetFrameName->vt) && varTargetFrameName->bstrVal)
|
|
{
|
|
IEFrameAuto * piefa = NULL;
|
|
|
|
hr = _pauto->QueryInterface(IID_PPV_ARG(IEFrameAuto, &piefa));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
hr = TargetQueryService((IShellBrowser *)piefa, IID_PPV_ARG(ITargetFrame2, &pTopTargetFrame));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pTopTargetFrame->FindFrame(
|
|
varTargetFrameName->bstrVal,
|
|
FINDFRAME_JUSTTESTEXISTENCE,
|
|
&punkTargetFrame);
|
|
if (SUCCEEDED(hr) && punkTargetFrame)
|
|
{
|
|
// yes, we found a frame with that name. QI for the automation
|
|
// interface on that frame.
|
|
hr = punkTargetFrame->QueryInterface(IID_PPV_ARG(IWebBrowser2, &pIWB2Target));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pIWB2Target->get_LocationURL(&bstrTargetUrl);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _pautoWB2->get_LocationURL(&bstrSrcUrl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
fAllowed = AccessAllowed(_pcli, bstrSrcUrl, bstrTargetUrl);
|
|
SysFreeString(bstrSrcUrl);
|
|
}
|
|
SysFreeString(bstrTargetUrl);
|
|
}
|
|
pIWB2Target->Release();
|
|
}
|
|
punkTargetFrame->Release();
|
|
}
|
|
pTopTargetFrame->Release();
|
|
}
|
|
piefa->Release();
|
|
}
|
|
}
|
|
return fAllowed;
|
|
}
|
|
|
|
|
|
// The SECURELOCK enumeration must be sorted in order of security level, and we may
|
|
// need to insert new values into the middle of the list in future. So we'll map
|
|
// the values to a set of constants.
|
|
|
|
BOOL SecureLockToIconConstant(int nSecureLock, LONG *plIconConstant)
|
|
{
|
|
BOOL fRet = TRUE;
|
|
|
|
switch (nSecureLock)
|
|
{
|
|
case SECURELOCK_SET_UNSECURE : *plIconConstant = secureLockIconUnsecure; break;
|
|
case SECURELOCK_SET_MIXED : *plIconConstant = secureLockIconMixed; break;
|
|
case SECURELOCK_SET_SECUREUNKNOWNBIT : *plIconConstant = secureLockIconSecureUnknownBits; break;
|
|
case SECURELOCK_SET_SECURE40BIT : *plIconConstant = secureLockIconSecure40Bit; break;
|
|
case SECURELOCK_SET_SECURE56BIT : *plIconConstant = secureLockIconSecure56Bit; break;
|
|
case SECURELOCK_SET_SECURE128BIT : *plIconConstant = secureLockIconSecure128Bit; break;
|
|
case SECURELOCK_SET_FORTEZZA : *plIconConstant = secureLockIconSecureFortezza; break;
|
|
default:
|
|
// Don't need to fire an event
|
|
fRet = FALSE;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
void CWebBrowserOC::_OnSetSecureLockIcon(int lock)
|
|
{
|
|
LONG lIconConstant;
|
|
|
|
if (SecureLockToIconConstant(lock, &lIconConstant))
|
|
{
|
|
// Fire the OnUpdateSecurityIcon event only from the DWebBrowserEvents2 connection point
|
|
|
|
VARIANTARG args[1];
|
|
IUnknown_CPContainerInvokeParam(_pautoEDS, DIID_DWebBrowserEvents2,
|
|
DISPID_SETSECURELOCKICON, args, 1, VT_I4, lIconConstant);
|
|
}
|
|
}
|
|
|
|
// CWebBrowserSB implementation
|
|
|
|
CWebBrowserSB::CWebBrowserSB(IUnknown* pauto, CWebBrowserOC* psvo)
|
|
: CBASEBROWSER(NULL)
|
|
, _psvo(psvo)
|
|
{
|
|
_Initialize(0, pauto);
|
|
}
|
|
|
|
CWebBrowserSB::~CWebBrowserSB()
|
|
{
|
|
}
|
|
|
|
HRESULT CWebBrowserSB::QueryInterface(REFIID riid, void ** ppvObj)
|
|
{
|
|
HRESULT hr = CBASEBROWSER::QueryInterface(riid, ppvObj);
|
|
|
|
if (FAILED(hr) && (riid == IID_IIsWebBrowserSB))
|
|
hr = CBASEBROWSER::QueryInterface(IID_IUnknown, ppvObj);
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL VirtualTopLevelBrowser(IOleClientSite * pcls)
|
|
{
|
|
IOleContainer * poc;
|
|
BOOL fNonStandard = FALSE;
|
|
|
|
if (SUCCEEDED(pcls->GetContainer(&poc)))
|
|
{
|
|
ITargetContainer * ptc;
|
|
|
|
// Is our container hosting us?
|
|
if (SUCCEEDED(poc->QueryInterface(IID_PPV_ARG(ITargetContainer, &ptc))))
|
|
{
|
|
fNonStandard = TRUE;
|
|
ptc->Release();
|
|
}
|
|
poc->Release();
|
|
}
|
|
|
|
return fNonStandard;
|
|
}
|
|
|
|
HRESULT CWebBrowserSB::SetTopBrowser()
|
|
{
|
|
HRESULT hres = CBASEBROWSER::SetTopBrowser();
|
|
|
|
if (_fTopBrowser && EVAL(_psvo))
|
|
_fNoTopLevelBrowser = VirtualTopLevelBrowser(_psvo->_pcli);
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
LRESULT CWebBrowserSB::WndProcBS(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT lret = CBASEBROWSER::WndProcBS(hwnd, uMsg, wParam, lParam);
|
|
|
|
switch(uMsg)
|
|
{
|
|
case WM_DESTROY:
|
|
// Because we won't get WM_NCDESTROY here, we should clean up
|
|
// this member variable here.
|
|
_bbd._hwnd = NULL;
|
|
break;
|
|
}
|
|
|
|
return lret;
|
|
}
|
|
|
|
// *** IOleWindow methods ***
|
|
|
|
// CBASEBROWSER maps SetStatusTextSB to SendControlMsg,
|
|
// so we don't need a CWebBrowserSB::SetStatusTextSB implementation.
|
|
|
|
HRESULT CWebBrowserSB::_EnableModeless(BOOL fEnable, BOOL fDirection)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
|
|
CBASEBROWSER::EnableModelessSB(fEnable);
|
|
|
|
if (fDirection == DIRECTION_FORWARD_TO_PARENT)
|
|
{
|
|
if (_psvo && _psvo->_pipframe)
|
|
{
|
|
hres = _psvo->_pipframe->EnableModeless(fEnable);
|
|
if (!fEnable && _psvo->_fHostedInVB5)
|
|
{
|
|
// APPHACK: VB5 -- If we haven't put up a dialog between the EnableModelessSB(FALSE) call and this
|
|
// call, we'll end up with a message on the queue that will disable all windows.
|
|
// Let's peek for this message and dispatch it if it is VB5's.
|
|
//
|
|
#define VBM_POSTENABLEMODELESS 0x1006
|
|
#define VBM_MAINCLASS1 TEXT("ThunderRT5Main")
|
|
#define VBM_MAINCLASS2 TEXT("ThunderRT6Main")
|
|
#define VBM_MAINCLASS3 TEXT("ThunderMain")
|
|
|
|
MSG msg;
|
|
HWND hwnd = NULL;
|
|
TCHAR strBuf[15];
|
|
|
|
if (PeekMessage( &msg, NULL, VBM_POSTENABLEMODELESS, VBM_POSTENABLEMODELESS, PM_NOREMOVE))
|
|
{
|
|
/* On Win95, apparently PeekMessage can return one type of message
|
|
* outside the range specified: WM_QUIT. Double-check the message we
|
|
* got back.
|
|
*/
|
|
if (msg.message == VBM_POSTENABLEMODELESS)
|
|
{
|
|
GetClassName(msg.hwnd, strBuf, sizeof(strBuf)/sizeof(strBuf[0]));
|
|
if (StrCmp(strBuf, VBM_MAINCLASS1) == 0 ||
|
|
StrCmp(strBuf, VBM_MAINCLASS2) == 0 ||
|
|
StrCmp(strBuf, VBM_MAINCLASS3) == 0)
|
|
{
|
|
PeekMessage( &msg, msg.hwnd, VBM_POSTENABLEMODELESS, VBM_POSTENABLEMODELESS, PM_REMOVE);
|
|
TraceMsg(TF_SHDCONTROL, "shv CWebBrowserSB::_EnableModeless dispatching VBM_POSTENABLEMODELESS" );
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If we're a subframe
|
|
// AND the EnableModeless(FALSE) count (_cRefCannotNavigate) has become zero
|
|
// AND our window is disabled
|
|
// THEN the likely scenario is that VB5 failed to reenable us. Trace it and reenable
|
|
// ourselves.
|
|
//
|
|
if (!_fTopBrowser
|
|
&& _cRefCannotNavigate == 0
|
|
&& GetWindowLong(_bbd._hwnd, GWL_STYLE) & WS_DISABLED)
|
|
{
|
|
TraceMsg(TF_WARNING, "shv Subframe was left disabled. Reenabling ourselves.");
|
|
EnableWindow(_bbd._hwnd, TRUE);
|
|
}
|
|
}
|
|
}
|
|
else if (_psvo && _psvo->_pcli)
|
|
{
|
|
IShellBrowser* psbParent;
|
|
if (SUCCEEDED(IUnknown_QueryService(_psvo->_pcli, SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &psbParent))))
|
|
{
|
|
psbParent->EnableModelessSB(fEnable);
|
|
psbParent->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IOIPAMSG(TEXT("_EnableModeless NOT forwarding on to _pipframe"));
|
|
}
|
|
}
|
|
else // DIRECTION_FORWARD_TO_CHILD
|
|
{
|
|
ASSERT(fDirection == DIRECTION_FORWARD_TO_CHILD);
|
|
if (_bbd._psv)
|
|
{
|
|
hres = _bbd._psv->EnableModelessSV(fEnable);
|
|
}
|
|
else
|
|
{
|
|
IOIPAMSG(TEXT("_EnableModeless NOT forwarding on to _psv"));
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CWebBrowserSB::EnableModelessSB(BOOL fEnable)
|
|
{
|
|
return _EnableModeless(fEnable, DIRECTION_FORWARD_TO_PARENT);
|
|
}
|
|
|
|
HRESULT CWebBrowserSB::_TranslateAccelerator(LPMSG lpmsg, WORD wID, BOOL fDirection)
|
|
{
|
|
// see if we handle it
|
|
HRESULT hr = CBASEBROWSER::TranslateAcceleratorSB(lpmsg, wID);
|
|
if (hr == S_OK)
|
|
{
|
|
IOIPAMSG(TEXT("_TranslateAccelerator: CBASEBROWSER's TranslateAcceleratorSB handled it"));
|
|
}
|
|
else if (fDirection == DIRECTION_FORWARD_TO_PARENT)
|
|
{
|
|
if (_psvo && _psvo->_pipframe)
|
|
{
|
|
hr = _psvo->_pipframe->TranslateAccelerator(lpmsg, wID);
|
|
}
|
|
else
|
|
{
|
|
IOIPAMSG(TEXT("_TranslateAccelerator NOT forwarding on to _pipframe"));
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
else // fDirection == DIRECTION_FORWARD_TO_CHILD
|
|
{
|
|
if (_bbd._psv)
|
|
{
|
|
hr = _bbd._psv->TranslateAccelerator(lpmsg);
|
|
}
|
|
else
|
|
{
|
|
IOIPAMSG(TEXT("_TranslateAccelerator NOT forwarding on to _psv"));
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CWebBrowserSB::TranslateAcceleratorSB(LPMSG lpmsg, WORD wID)
|
|
{
|
|
return _TranslateAccelerator(lpmsg, wID, DIRECTION_FORWARD_TO_PARENT);
|
|
}
|
|
|
|
HRESULT CWebBrowserSB::SendControlMsg(UINT id, UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, LRESULT * pret)
|
|
{
|
|
// let CBASEBROWSER try first so we get automation notifications working
|
|
HRESULT hres = CBASEBROWSER::SendControlMsg(id, uMsg, wParam, lParam, pret);
|
|
|
|
// if we're in a blocking frame, our GetControlWindow above will fail
|
|
// causing CBASEBROWSER to fail. try to map to an IOleInPlaceFrame call.
|
|
if (FAILED(hres) && _psvo)
|
|
{
|
|
// forward status bar text changes to the frame.
|
|
if ((id == FCW_STATUS) &&
|
|
(uMsg == SB_SETTEXT || uMsg == SB_SETTEXTW) && // trying to set status text
|
|
(!(wParam & SBT_OWNERDRAW)) && // we don't own the window -- this can't work
|
|
(((wParam & 0x00FF) == 0x00FF) || ((wParam & 0x00FF)== 0))) // simple or 0th item
|
|
{
|
|
WCHAR szStatusText[256];
|
|
|
|
if (uMsg == SB_SETTEXT) {
|
|
if (lParam)
|
|
{
|
|
SHTCharToUnicode((LPTSTR)lParam, szStatusText, ARRAYSIZE(szStatusText));
|
|
}
|
|
else
|
|
{
|
|
szStatusText[0] = L'\0';
|
|
}
|
|
|
|
lParam = (LPARAM) szStatusText;
|
|
}
|
|
else if (!lParam)
|
|
{
|
|
// uMsg == SB_SETTEXTW
|
|
// Found a container that doesn't like null string pointers. Pass an empty string instead.
|
|
// (IE v 4.1 bug 64629)
|
|
szStatusText[0] = 0;
|
|
lParam = (LPARAM) szStatusText;
|
|
}
|
|
|
|
if (_psvo->_pipframe)
|
|
{
|
|
if (pret)
|
|
{
|
|
*pret = 0;
|
|
}
|
|
hres = _psvo->_pipframe->SetStatusText((LPCOLESTR)lParam);
|
|
}
|
|
else
|
|
{
|
|
IOIPAMSG(TEXT("SetStatusTextSB NOT forwarding on to _pipframe"));
|
|
}
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
HRESULT CWebBrowserSB::OnViewWindowActive(struct IShellView * psv)
|
|
{
|
|
if (_psvo)
|
|
{
|
|
// The view is notifying us that it just went UIActive,
|
|
// we need to update our state. OC_UIACTIVE normally
|
|
// tells the view to UIActivate itself, but in this case
|
|
// it already is. Avoid an infinite loop and pass FALSE.
|
|
_psvo->_DoActivateChange(NULL, OC_UIACTIVE, FALSE);
|
|
}
|
|
|
|
return CBASEBROWSER::OnViewWindowActive(psv);
|
|
}
|
|
|
|
|
|
LRESULT CWebBrowserSB::_DefWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// explicitly do nothing...
|
|
// this is just to override CBASEBROWSER's _DefWindowProc.
|
|
return 0;
|
|
}
|
|
|
|
void CWebBrowserSB::_ViewChange(DWORD dwAspect, LONG lindex)
|
|
{
|
|
//
|
|
// forward this notify up to the OC's OBJECTCODE_VIEWCHANGE handler so it
|
|
// gets forwarded on to our container.
|
|
//
|
|
if (_psvo)
|
|
_psvo->_ViewChange(dwAspect, lindex);
|
|
|
|
//
|
|
// also let the base browser handle this view change in case nobody else is
|
|
// handling palette messages. most of the time this will be a nop but in
|
|
// the case where a WM_QUERYNEWPALETTE makes it down to us this will allow
|
|
// us to manage the palette properly.
|
|
//
|
|
CBASEBROWSER::_ViewChange(dwAspect, lindex);
|
|
}
|
|
|
|
HRESULT CWebBrowserSB::ActivatePendingView()
|
|
{
|
|
CVOCBMSG(TEXT("_ActivatePendingView"));
|
|
|
|
// CBASEBROWSER::_ActivatePendingView will send a NavigateComplete
|
|
// event. During this event our parent may destroy us. We then fault
|
|
// dereferencing _psvo below. So we need to wrap this function with
|
|
// an AddRef/Release. (bug 15424)
|
|
//
|
|
AddRef();
|
|
|
|
HRESULT hres = CBASEBROWSER::ActivatePendingView();
|
|
|
|
if (SUCCEEDED(hres) && _psvo)
|
|
_psvo->_OnSetShellView(_bbd._psv);
|
|
|
|
Release();
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CWebBrowserSB::ReleaseShellView(void)
|
|
{
|
|
CVOCBMSG(TEXT("_ReleaseShellView"));
|
|
|
|
if (_psvo)
|
|
_psvo->_OnReleaseShellView();
|
|
|
|
return CBASEBROWSER::ReleaseShellView();
|
|
}
|
|
|
|
|
|
/// IBrowserService stuff
|
|
HRESULT CWebBrowserSB::GetParentSite(struct IOleInPlaceSite** ppipsite)
|
|
{
|
|
HRESULT hres = E_FAIL; // assume error
|
|
*ppipsite = NULL; // assume error
|
|
|
|
if (_psvo)
|
|
{
|
|
if (_psvo->_pipsite)
|
|
{
|
|
*ppipsite = _psvo->_pipsite;
|
|
_psvo->_pipsite->AddRef();
|
|
hres = S_OK;
|
|
}
|
|
else if (_psvo->_pcli)
|
|
{
|
|
hres = _psvo->_pcli->QueryInterface(IID_PPV_ARG(IOleInPlaceSite, ppipsite));
|
|
}
|
|
else
|
|
{
|
|
// Is it expected?
|
|
TraceMsg(DM_WARNING, "CWBSB::GetParentSite called when _pcli is NULL");
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
#ifdef FEATURE_FRAMES
|
|
HRESULT CWebBrowserSB::GetOleObject(struct IOleObject** ppobjv)
|
|
{
|
|
if (_psvo == NULL)
|
|
{
|
|
*ppobjv = NULL;
|
|
return E_FAIL;
|
|
}
|
|
return _psvo->QueryInterface(IID_PPV_ARG(IOleObject, ppobjv));
|
|
}
|
|
#endif
|
|
|
|
HRESULT CWebBrowserSB::SetNavigateState(BNSTATE bnstate)
|
|
{
|
|
// Do our own things (such as firing events and update _fNavigate).
|
|
HRESULT hres = CBASEBROWSER::SetNavigateState(bnstate);
|
|
|
|
//
|
|
// Then, tell the container to update the download state.
|
|
// This will start the animation if this OC is either in a frameset
|
|
// or in a browser band.
|
|
//
|
|
VARIANTARG var;
|
|
var.vt = VT_I4;
|
|
var.lVal = _fNavigate;
|
|
Exec(NULL, OLECMDID_SETDOWNLOADSTATE, 0, &var, NULL);
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
LRESULT CWebBrowserSB::OnNotify(LPNMHDR pnm)
|
|
{
|
|
switch(pnm->code)
|
|
{
|
|
case SEN_DDEEXECUTE:
|
|
{
|
|
IShellBrowser *psbTop;
|
|
if (pnm->idFrom == 0 && SUCCEEDED(_QueryServiceParent(SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser, &psbTop))))
|
|
{
|
|
HWND hwndTop;
|
|
|
|
psbTop->GetWindow(&hwndTop);
|
|
psbTop->Release();
|
|
if (psbTop != this)
|
|
return SendMessage(hwndTop, WM_NOTIFY, 0, (LPARAM)pnm);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return CBASEBROWSER::OnNotify(pnm);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// IServiceProvider stuff
|
|
//
|
|
|
|
HRESULT CWebBrowserSB::_QueryServiceParent(REFGUID guidService, REFIID riid, void **ppvObj)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
|
|
*ppvObj = NULL;
|
|
|
|
// Pass it on to our parent
|
|
if (_psvo && _psvo->_pcli)
|
|
{
|
|
hres = IUnknown_QueryService(_psvo->_pcli, guidService, riid, ppvObj);
|
|
}
|
|
else
|
|
{
|
|
CVOCBMSG(TEXT("QueryService doesn't have _pipsite!"));
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
// NOTES:
|
|
// If SID_STopLevelBrowser, go to parent (upto the top level browser)
|
|
// If SID_SWebBrowserApp, go to parent (up to the top level browser automation)
|
|
// If SID_SContainerDispatch, expose CWebBrowserOC (instead of _pauto)
|
|
// Then, try CBASEBROWSER::QueryService, which will handle SID_SHlinkFrame,
|
|
// SID_SUrlHistory, SID_SShellBrowser, etc.
|
|
// If all fails and not SID_SShellBrowser, then we go up the parent chain.
|
|
//
|
|
HRESULT CWebBrowserSB::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
|
|
{
|
|
HRESULT hr = E_FAIL; // service object not found
|
|
|
|
*ppvObj = NULL; // assume error
|
|
|
|
// if the guidService is SID_QIClientSite then delegate the iid to the
|
|
// container through a queryinterface call.
|
|
if (_psvo && _psvo->_pcli && IsEqualGUID( guidService, SID_QIClientSite))
|
|
{
|
|
return _psvo->_pcli->QueryInterface( riid, ppvObj);
|
|
}
|
|
|
|
// If guidService is SID_STopLevelBrowser, we should not ask the super
|
|
// class to handle. Instead, we ask the parent to handle (if any).
|
|
if (IsEqualGUID(guidService, SID_STopLevelBrowser) ||
|
|
IsEqualGUID(guidService, SID_STopWindow))
|
|
{
|
|
// APPCOMPAT: WebBrowser is not supposed to respond to QS(SID_SInetExp) because
|
|
// it does not support IWebBrowserApp. However, rejecting this causes
|
|
// a stack fault when opening a frame-set. We need to find out what is causing
|
|
// this stack fault but I'll backup this delta for now to stop GPF.
|
|
//
|
|
// || IsEqualGUID(guidService, SID_SWebBrowserApp)
|
|
goto AskParent;
|
|
}
|
|
|
|
if (IsEqualGUID(guidService, SID_STopFrameBrowser))
|
|
{
|
|
BOOL fAskParent = TRUE;
|
|
|
|
// Don't ask the parent if we are a desktop component and we are
|
|
// not doing drag/drop. Treat it as a top level frame. For all other
|
|
// cases, ask the parent.
|
|
if (!IsEqualIID(riid, IID_IDropTarget) && _ptfrm)
|
|
{
|
|
IUnknown *pUnkParent;
|
|
if (SUCCEEDED(_ptfrm->GetParentFrame(&pUnkParent)))
|
|
{
|
|
if (pUnkParent)
|
|
{
|
|
// Has a parent, not a desktop component
|
|
pUnkParent->Release();
|
|
}
|
|
else
|
|
{
|
|
// Doesn't have a parent, must be a desktop component so
|
|
// fall through to call our CBASEBROWSER::QueryService
|
|
fAskParent = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fAskParent)
|
|
goto AskParent;
|
|
}
|
|
|
|
// If the containee is asking for SID_SContainerDispatch (parent),
|
|
// we should return the automation interface of the buddy CWebBrowserOC.
|
|
if (IsEqualGUID(guidService, SID_SContainerDispatch))
|
|
{
|
|
if (_psvo)
|
|
{
|
|
return _psvo->QueryInterface(riid, ppvObj);
|
|
}
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
// If the guidService is SID_SVersionHost,
|
|
// give the host a crack at it first
|
|
//
|
|
if (IsEqualGUID(guidService, SID_SVersionHost))
|
|
{
|
|
hr = _QueryServiceParent(guidService, riid, ppvObj);
|
|
|
|
// Return if the host handled the service,
|
|
//
|
|
if (S_OK == hr)
|
|
return hr;
|
|
}
|
|
|
|
hr = CBASEBROWSER::QueryService(guidService, riid, ppvObj);
|
|
|
|
// Notes: If guidService is SID_SShellBrowser, it indicates that
|
|
// the caller wants to talk to the immediate IShellBrowser.
|
|
// We should not try our parent in that case. Doing it so will
|
|
// break nested browser (frame set). In addition, notice that
|
|
// we don't want to go up the parent chain if hr is E_NOINTERFACE
|
|
// (which indicates unsuccessfull QueryInterface).
|
|
//
|
|
// We don't want a shell view in a frame-set add buttons on the
|
|
// toolbar. We should skip AskParent if guidService is SID_SExplroerToolbar.
|
|
|
|
if (FAILED(hr) && hr != E_NOINTERFACE
|
|
&& !IsEqualIID(guidService, SID_SShellBrowser)
|
|
&& !IsEqualIID(guidService, SID_SExplorerToolbar))
|
|
{
|
|
AskParent:
|
|
hr = _QueryServiceParent(guidService, riid, ppvObj);
|
|
|
|
// hey, we're the top-level browser if there ain't no top-level browser
|
|
// above us. (Such as our OC embedded in AOL/CIS/VB.) We must do this
|
|
// or we don't get a _tlGlobal on the top frame, so navigation history
|
|
// is screwy and the back/forward buttons are incorrect.
|
|
if (FAILED(hr) &&
|
|
(IsEqualGUID(guidService, SID_STopLevelBrowser) ||
|
|
IsEqualGUID(guidService, SID_STopFrameBrowser) ||
|
|
IsEqualGUID(guidService, SID_STopWindow)))
|
|
{
|
|
hr = CBASEBROWSER::QueryService(guidService, riid, ppvObj);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
// IOleCommandTarget
|
|
//
|
|
// We simply forward to the container above our parent OC
|
|
|
|
HRESULT CWebBrowserSB::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
|
|
{
|
|
HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
|
|
HRESULT hresLocal;
|
|
|
|
if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CGID_ShellDocView))
|
|
{
|
|
hres = S_OK;
|
|
for (ULONG i=0 ; i < cCmds ; i++)
|
|
{
|
|
if (rgCmds[i].cmdID == SHDVID_CANGOBACK ||
|
|
rgCmds[i].cmdID == SHDVID_CANGOFORWARD)
|
|
{
|
|
hresLocal = CBASEBROWSER::QueryStatus(pguidCmdGroup, 1, &rgCmds[i], pcmdtext);
|
|
}
|
|
else if (_psvo && _psvo->_pctContainer)
|
|
{
|
|
hresLocal = _psvo->_pctContainer->QueryStatus(pguidCmdGroup, 1, &rgCmds[i], pcmdtext);
|
|
|
|
if (hresLocal == OLECMDERR_E_UNKNOWNGROUP || hresLocal == OLECMDERR_E_NOTSUPPORTED)
|
|
{
|
|
hresLocal = CBASEBROWSER::QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
|
|
}
|
|
}
|
|
else
|
|
hresLocal = OLECMDERR_E_NOTSUPPORTED;
|
|
if (hresLocal != S_OK) hres = hresLocal;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_psvo && _psvo->_pctContainer)
|
|
hres = _psvo->_pctContainer->QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
|
|
|
|
// if container does not support the command try base browser
|
|
// before we only used to return an error
|
|
if (hres == OLECMDERR_E_UNKNOWNGROUP || hres == OLECMDERR_E_NOTSUPPORTED)
|
|
{
|
|
hres = CBASEBROWSER::QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
struct WBCMDLIST {
|
|
const GUID* pguidCmdGroup;
|
|
DWORD nCmdID;
|
|
};
|
|
|
|
//
|
|
// SBCMDID_CANCELNAVIGATION:
|
|
// Don't pass SBCMDID_CANCELNAVIGATION up to ROOT browser. Canceling
|
|
// here doesn't need to be forwarded and will cause navigations of to
|
|
// initiated by javascript: navigations in this frame to be aborted.
|
|
//
|
|
// SHDVID_ACTIVATEMENOW:
|
|
// The DocHost's request to activate the pending view must be handled
|
|
// by THIS browser, not the parent's -- if we're in a frameset page,
|
|
// we've probably already activated the top-level browser, now we may
|
|
// be trying to activate an individual frame.
|
|
//
|
|
const WBCMDLIST c_acmdWBSB[] = {
|
|
{ NULL, OLECMDID_HTTPEQUIV },
|
|
{ NULL, OLECMDID_HTTPEQUIV_DONE },
|
|
{ &CGID_ShellDocView, SHDVID_GETPENDINGOBJECT },
|
|
{ &CGID_ShellDocView, SHDVID_ACTIVATEMENOW },
|
|
{ &CGID_ShellDocView, SHDVID_DOCFAMILYCHARSET },
|
|
{ &CGID_Explorer, SBCMDID_CANCELNAVIGATION },
|
|
{ &CGID_Explorer, SBCMDID_CREATESHORTCUT },
|
|
{ &CGID_ShellDocView, SHDVID_CHECKINCACHEIFOFFLINE },
|
|
{ &CGID_ShellDocView, SHDVID_SETPRINTSTATUS },
|
|
{ &CGID_ShellDocView, SHDVID_FIREFILEDOWNLOAD },
|
|
{ &CGID_DocHostCmdPriv, DOCHOST_DOCCANNAVIGATE },
|
|
{ &CGID_InternetExplorer, IECMDID_BEFORENAVIGATE_GETSHELLBROWSE },
|
|
{ &CGID_InternetExplorer, IECMDID_BEFORENAVIGATE_DOEXTERNALBROWSE },
|
|
{ &CGID_InternetExplorer, IECMDID_BEFORENAVIGATE_GETIDLIST },
|
|
{ &CGID_InternetExplorer, IECMDID_SET_INVOKE_DEFAULT_BROWSER_ON_NEW_WINDOW },
|
|
{ &CGID_InternetExplorer, IECMDID_GET_INVOKE_DEFAULT_BROWSER_ON_NEW_WINDOW },
|
|
{ &CGID_DocHostCmdPriv, DOCHOST_SETBROWSERINDEX },
|
|
};
|
|
|
|
HRESULT CWebBrowserSB::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
|
|
{
|
|
HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
|
|
|
|
//
|
|
// First, test if the spcified command is supposed to processed by
|
|
// this browser or not. If that's the case, just call CBASEBROWSER::Exec
|
|
// and return.
|
|
//
|
|
for (int i=0; i<ARRAYSIZE(c_acmdWBSB); i++)
|
|
{
|
|
if (nCmdID == c_acmdWBSB[i].nCmdID)
|
|
{
|
|
if (pguidCmdGroup==NULL || c_acmdWBSB[i].pguidCmdGroup==NULL)
|
|
{
|
|
if (pguidCmdGroup==c_acmdWBSB[i].pguidCmdGroup)
|
|
{
|
|
return CBASEBROWSER::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
}
|
|
}
|
|
else if (IsEqualGUID(*pguidCmdGroup, *c_acmdWBSB[i].pguidCmdGroup))
|
|
{
|
|
return CBASEBROWSER::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
}
|
|
}
|
|
}
|
|
|
|
// In some cases, we need perform some additional operations
|
|
// before passing it to the parent.
|
|
//
|
|
if (pguidCmdGroup == NULL)
|
|
{
|
|
switch(nCmdID) {
|
|
case OLECMDID_SETDOWNLOADSTATE:
|
|
if (pvarargIn)
|
|
{
|
|
_setDescendentNavigate(pvarargIn);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (IsEqualGUID(*pguidCmdGroup, CGID_ShellDocView))
|
|
{
|
|
switch (nCmdID)
|
|
{
|
|
/* The DocHost's request to activate the pending view must be handled
|
|
* by THIS browser, not the parent's -- then we forward up the chain
|
|
* so that all potentially blocked frames can attempt to deactivate
|
|
*/
|
|
case SHDVID_DEACTIVATEMENOW:
|
|
if (_cbScriptNesting > 0)
|
|
_cbScriptNesting--;
|
|
hres = CBASEBROWSER::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
if (FAILED(hres) || _cbScriptNesting > 0)
|
|
return hres;
|
|
break;
|
|
|
|
case SHDVID_NODEACTIVATENOW:
|
|
_cbScriptNesting++;
|
|
if (_cbScriptNesting > 1)
|
|
return S_OK;
|
|
break;
|
|
|
|
case SHDVID_DELEGATEWINDOWOM:
|
|
if (_psvo && _psvo->_pauto)
|
|
{
|
|
// Forward this command to the CIEFrameAuto instance for this webOC.
|
|
return IUnknown_Exec(_psvo->_pauto, &CGID_ShellDocView, nCmdID, 0, pvarargIn, NULL);
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
else if (IsEqualGUID(*pguidCmdGroup, CGID_Explorer))
|
|
{
|
|
// this needs to be handled by the specific browser that
|
|
// received the exec.
|
|
switch (nCmdID)
|
|
{
|
|
case SBCMDID_UPDATETRAVELLOG:
|
|
case SBCMDID_REPLACELOCATION:
|
|
return CBASEBROWSER::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
|
|
case SBCMDID_SETSECURELOCKICON:
|
|
{
|
|
CBASEBROWSER::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
|
|
// Let the WebBrowserOC fire the event
|
|
if (_psvo)
|
|
{
|
|
_psvo->_OnSetSecureLockIcon(_bbd._eSecureLockIcon);
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
}
|
|
else if (IsEqualGUID(CGID_ExplorerBarDoc, *pguidCmdGroup))
|
|
{
|
|
// These are ignored so that Explorer bar changes are done once - and only in response to
|
|
// global changes applied to top Document if frameset of browser.
|
|
// NOT for changes applied to frames
|
|
// NOT for changes applied to browserbands
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Forward this EXEC to the container (if we have).
|
|
//
|
|
if (_psvo && _psvo->_pctContainer)
|
|
hres = _psvo->_pctContainer->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
|
|
//
|
|
// if the above exec failed, we're probably in some random container
|
|
// so let CBASEBROWSER try to simulate a top-level frame.
|
|
// might as well be a bit paranoid and make sure it failed with "i dunno"
|
|
//
|
|
if (hres == OLECMDERR_E_UNKNOWNGROUP || hres == OLECMDERR_E_NOTSUPPORTED)
|
|
{
|
|
if (pguidCmdGroup==NULL && nCmdID==OLECMDID_SETDOWNLOADSTATE && _psvo)
|
|
{
|
|
TraceMsg(DM_FORSEARCHBAND, "WBSB::QueryStatus Container does not support OLECMDID_SETDOWNLOADSTATE");
|
|
hres = _psvo->_SetDownloadState(hres, nCmdexecopt, pvarargIn);
|
|
}
|
|
|
|
if (hres != S_OK)
|
|
{
|
|
hres = CBASEBROWSER::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
HRESULT CWebBrowserSB::_SwitchActivationNow()
|
|
{
|
|
CBASEBROWSER::_SwitchActivationNow();
|
|
|
|
if (_bbd._psv &&
|
|
_psvo &&
|
|
_psvo->_nActivate < OC_INPLACEACTIVE &&
|
|
_psvo->_dwDrawAspect)
|
|
{
|
|
// pass on the SetExtent to the now ready browser...
|
|
IPrivateOleObject * pPrivOle;
|
|
if (SUCCEEDED(_bbd._psv->QueryInterface(IID_PPV_ARG(IPrivateOleObject, &pPrivOle))))
|
|
{
|
|
// we have an ole object, delegate downwards...
|
|
pPrivOle->SetExtent( _psvo->_dwDrawAspect, &_psvo->_sizeHIM );
|
|
pPrivOle->Release();
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
BOOL CWebBrowserSB::_HeyMoe_IsWiseGuy()
|
|
{
|
|
BOOL fRet;
|
|
|
|
if (_psvo)
|
|
{
|
|
fRet = _psvo->_HeyMoe_IsWiseGuy();
|
|
}
|
|
else
|
|
{
|
|
fRet = FALSE;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
HRESULT CWebBrowserSB::BrowseObject(LPCITEMIDLIST pidl, UINT wFlags)
|
|
{
|
|
// if client does not specify we will do so for them
|
|
if (SBSP_DEFBROWSER == (wFlags & (SBSP_NEWBROWSER | SBSP_SAMEBROWSER)))
|
|
{
|
|
IShellBrowser *psbDesktop;
|
|
if (SUCCEEDED(QueryService(SID_SShellDesktop, IID_PPV_ARG(IShellBrowser, &psbDesktop))))
|
|
{
|
|
HRESULT hr = psbDesktop->BrowseObject(pidl, wFlags);
|
|
psbDesktop->Release();
|
|
return hr;
|
|
}
|
|
wFlags |= SBSP_SAMEBROWSER; // always navigate in place
|
|
}
|
|
|
|
return CBASEBROWSER::BrowseObject(pidl, wFlags);
|
|
}
|
|
|