Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

10114 lines
283 KiB

#include "priv.h"
#include "sccls.h"
#include "hlframe.h"
#include <iethread.h>
#include <shobjidlp.h>
#include "stdenum.h"
#include "winlist.h"
#include "iedde.h"
#include "bindcb.h" // for CStubBindStatusCallback
#include "mshtmdid.h"
#include "resource.h"
#include "security.h"
#include "htregmng.h"
#include "mlang.h" // for GetRfc1766FromLcid
#include "winver.h"
#include "dhuihand.h" // for GetFindDialogUp()
#include <varutil.h>
#include <mluisupp.h>
#define DM_FRAMEPROPERTY 0
#define TO_VARIANT_BOOL(b) (b?VARIANT_TRUE:VARIANT_FALSE)
// If URL contains \1 in the string then the URL is really an empty url with the
// security information following the 0x01.
#define EMPTY_URL 0x01
EXTERN_C const IID IID_IProvideMultipleClassInfo;
#ifndef HLNF_EXTERNALNAVIGATE
#define HLNF_EXTERNALNAVIGATE 0x10000000
#endif
#define NAVFAIL_URL TEXT("about:NavigationFailure")
#define NAVFAIL_URL_DESKTOPITEM TEXT("about:DesktopItemNavigationFailure")
#define CPMSG(psz) TraceMsg(TF_SHDAUTO, "ief ConnectionPoint::%s", psz)
#define CPMSG2(psz,d) TraceMsg(TF_SHDAUTO, "ief ConnectionPoint::%s %x", psz, d)
#define DM_CPC 0
// Are there other definitions for these? Particularly MSIE
// We need some reasonable defaults in case we can't get the user agent string from the registry.
//
#define MSIE L"Microsoft Internet Explorer"
#define APPCODENAME L"Mozilla"
#define APPVERSION L"4.0 (compatible; MSIE 6.0)"
#define USERAGENT L"Mozilla/4.0 (compatible; MSIE 6.0)"
#define NO_NAME_NAME L"_No__Name:"
#define EXTENDER_DISPID_BASE ((ULONG)(0x80010000))
#define IS_EXTENDER_DISPID(x) (((ULONG)(x) & 0xFFFF0000) == EXTENDER_DISPID_BASE)
BOOL GetNextOption(BSTR& bstrOptionString, BSTR* optionName, int* piValue);
BSTR GetNextToken(BSTR bstr, BSTR delimiters, BSTR whitespace, BSTR *nextPos);
DWORD OpenAndNavigateToURL(CIEFrameAuto*, BSTR *, const WCHAR*, ITargetNotify*, BOOL bNoHistory, BOOL bSilent);
HRESULT __cdecl DoInvokeParamHelper(IUnknown* punk, IConnectionPoint* pccp, LPBOOL pf, void **ppv, DISPID dispid, UINT cArgs, ...);
BSTR SafeSysAllocStringLen(const WCHAR *pStr, const unsigned int len);
//====================================================================================
// Define a new internal class that is used to manage a set of simple properties that
// we manage as part of the object. This is mainly used such that pages (or objects
// that manage a page can save state across pages.
class CIEFrameAutoProp
{
public:
HRESULT Initialize(BSTR szProperty)
{
UINT cch = lstrlenW(szProperty);
if (cch < ARRAYSIZE(_sstr.wsz)) {
StrCpyNW(_sstr.wsz, szProperty, ARRAYSIZE(_sstr.wsz));
_sstr.cb = cch * sizeof(WCHAR);
_szProperty = _sstr.wsz;
return S_OK;
}
_szProperty = SysAllocString(szProperty);
return _szProperty ? S_OK : E_OUTOFMEMORY;
}
HRESULT SetValue(VARIANT *pvtValue, IWebBrowser2* pauto);
HRESULT CopyValue(VARIANT *pvtValue);
BOOL IsExpired(DWORD dwCur);
BOOL IsOurProp(BSTR szProperty) { return StrCmpW(szProperty, _szProperty) == 0;}
CIEFrameAutoProp * Next() {return _next;}
CIEFrameAutoProp () { VariantInit(&_vtValue); }
~CIEFrameAutoProp()
{
if (_szProperty && _szProperty != _sstr.wsz)
SysFreeString(_szProperty);
_VariantClear();
}
void _VariantClear();
CIEFrameAutoProp *_next;
protected:
BSTR _szProperty;
VARIANT _vtValue;
SA_BSTRGUID _sstr;
BOOL _fDiscardable : 1;
BOOL _fOwned : 1; // call SetSite(NULL) when discard
DWORD _dwLastAccessed;
} ;
#ifdef DEBUG
#define MSEC_PROPSWEEP (1*1000)
#define MSEC_PROPEXPIRE (5*1000)
#else
#define MSEC_PROPSWEEP (5*1000*60) // sweep every 5 min
#define MSEC_PROPEXPIRE (10*1000*60) // expire in 10 min
#endif
void CIEFrameAutoProp::_VariantClear()
{
if (_vtValue.vt == VT_UNKNOWN && _fOwned)
{
_fOwned = FALSE;
HRESULT hr = IUnknown_SetSite(_vtValue.punkVal, NULL);
ASSERT(SUCCEEDED(hr));
}
VariantClearLazy(&_vtValue);
}
HRESULT CIEFrameAutoProp::SetValue(VARIANT *pvtValue, IWebBrowser2* pauto)
{
TraceMsg(DM_FRAMEPROPERTY, "CIEFAP::SetValue called");
_dwLastAccessed = GetCurrentTime();
// In case we have _fOwned==TRUE.
_VariantClear();
if (pvtValue->vt == VT_UNKNOWN && pvtValue->punkVal)
{
// Check if this is discardable or not.
IUnknown* punk;
if (SUCCEEDED(pvtValue->punkVal->QueryInterface(IID_IDiscardableBrowserProperty, (void **)&punk)))
{
TraceMsg(DM_FRAMEPROPERTY, "CIEFAP::SetValue adding a discardable");
_fDiscardable = TRUE;
punk->Release();
}
//
// Check if we need to call SetSite(NULL) when we discard.
//
IObjectWithSite* pows;
HRESULT hresT = pvtValue->punkVal->QueryInterface(IID_PPV_ARG(IObjectWithSite, &pows));
if (SUCCEEDED(hresT))
{
IUnknown* psite;
hresT = pows->GetSite(IID_PPV_ARG(IUnknown, &psite));
if (SUCCEEDED(hresT) && psite)
{
_fOwned = IsSameObject(psite, pauto);
psite->Release();
}
pows->Release();
}
}
if (pvtValue->vt & VT_BYREF)
return VariantCopyInd(&_vtValue, pvtValue);
else
return VariantCopyLazy(&_vtValue, pvtValue);
}
HRESULT CIEFrameAutoProp::CopyValue(VARIANT *pvtValue)
{
_dwLastAccessed = GetCurrentTime();
return VariantCopyLazy(pvtValue, &_vtValue);
}
BOOL CIEFrameAutoProp::IsExpired(DWORD dwCur)
{
BOOL fExpired = FALSE;
if (_fDiscardable) {
fExpired = ((dwCur - _dwLastAccessed) > MSEC_PROPEXPIRE);
}
return fExpired;
}
//IDispatch functions, now part of IWebBrowserApp
STDAPI SafeGetItemObject(LPSHELLVIEW psv, UINT uItem, REFIID riid, void **ppv);
HRESULT CIEFrameAuto::v_InternalQueryInterface(REFIID riid, void ** ppvObj)
{
static const QITAB qit[] = {
// perf: last tuned 980728
QITABENT(CIEFrameAuto, IConnectionPointContainer), // IID_ConnectionPointContainer
QITABENT(CIEFrameAuto, IWebBrowser2), // IID_IWebBrowser2
QITABENT(CIEFrameAuto, IServiceProvider), // IID_IServiceProvider
QITABENTMULTI(CIEFrameAuto, IWebBrowserApp, IWebBrowser2), // IID_IWebBrowserApp
QITABENT(CIEFrameAuto, IShellService), // IID_IShellService
QITABENT(CIEFrameAuto, IEFrameAuto), // IID_IEFrameAuto
QITABENT(CIEFrameAuto, IExpDispSupport), // IID_IExpDispSupport
QITABENT(CIEFrameAuto, IWebBrowserPriv), // IID_IWebBrowserPriv
QITABENT(CIEFrameAuto, ITargetFrame2), // IID_ITargetFrame2
QITABENT(CIEFrameAuto, IHlinkFrame), // IID_IHlinkFrame
QITABENT(CIEFrameAuto, IOleCommandTarget), // IID_IOleCommandTarget
QITABENT(CIEFrameAuto, IUrlHistoryNotify), // IID_IUrlHistoryNotify
QITABENTMULTI(CIEFrameAuto, IDispatch, IWebBrowser2), // rare IID_IDispatch
QITABENTMULTI(CIEFrameAuto, IWebBrowser, IWebBrowser2),// rare IID_IWebBrowser
QITABENT(CIEFrameAuto, IExternalConnection), // rare IID_IExternalConnection
QITABENT(CIEFrameAuto, ITargetNotify), // rare IID_ITargetNotify
QITABENT(CIEFrameAuto, ITargetFramePriv), // rare IID_ITargetFramePriv
{ 0 },
};
HRESULT hres = QISearch(this, qit, riid, ppvObj);
if (FAILED(hres))
{
if (IsEqualIID(riid, IID_ITargetFrame))
{
*ppvObj = SAFECAST(&_TargetFrame, ITargetFrame*);
AddRef();
return S_OK;
}
}
return hres;
}
LONG CIEFrameAuto::s_cIEFrameAuto = 0;
CIEFrameAuto::CIEFrameAuto(IUnknown* punkAgg) :
m_dwFrameMarginWidth(0xFFFFFFFF)
,m_dwFrameMarginHeight(0xFFFFFFFF)
,CImpIDispatch(LIBID_SHDocVw, 1, 1, IID_IWebBrowser2)
,CAggregatedUnknown(punkAgg)
{
TraceMsg(TF_SHDLIFE, "ctor CIEFrameAuto %x", this);
//
// REVIEW: We don't need to DllAddRef as long as all instances
// of CIEFrameAuto are scoped by either CShellBrowser/CExplorerBrowser
// or CWebBrowserOC. We can remove the DllAddRef/Release, but it's not
// a perf hit so why bother??
//
DllAddRef();
InterlockedIncrement(&s_cIEFrameAuto);
ASSERT(_cLocks==0);
ASSERT(_pITI==NULL);
ASSERT(_pbs==NULL);
ASSERT(_hwnd==NULL);
ASSERT(_pProps==NULL);
ASSERT(_phlbc == NULL);
ASSERT(_dwRegHLBC == 0);
ASSERT(m_bOffline==FALSE);
ASSERT(m_bSilent==FALSE);
ASSERT(_hinstMSHTML==0);
ASSERT(_pfnMEGetIDsOfNames==0);
ASSERT(0==_pwszShortcutPath);
TraceMsg(TF_SHDLIFE, "ctor CIEFrameAuto(%x) being constructed", this);
m_cpWebBrowserEvents.SetOwner(_GetInner(), &DIID_DWebBrowserEvents);
m_cpWebBrowserEvents2.SetOwner(_GetInner(), &DIID_DWebBrowserEvents2);
m_cpPropNotify.SetOwner(_GetInner(), &IID_IPropertyNotifySink);
HRESULT hr = _omwin.Init();
ASSERT(SUCCEEDED(hr));
hr = _omloc.Init();
ASSERT(SUCCEEDED(hr));
hr = _omnav.Init(&_mimeTypes, &_plugins, &_profile);
ASSERT(SUCCEEDED(hr));
hr = _omhist.Init();
ASSERT(SUCCEEDED(hr));
hr = _mimeTypes.Init();
ASSERT(SUCCEEDED(hr));
hr = _plugins.Init();
ASSERT(SUCCEEDED(hr));
hr = _profile.Init();
ASSERT(SUCCEEDED(hr));
}
HRESULT CIEFrameAuto_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk)
{
CIEFrameAuto * pauto = new CIEFrameAuto(pUnkOuter);
if (pauto) {
*ppunk = pauto->_GetInner();
return S_OK;
}
*ppunk = NULL;
return E_OUTOFMEMORY;
}
STDAPI_(void) DestroyHdpaHooks(); // implemented in url.cpp
CIEFrameAuto::~CIEFrameAuto()
{
ASSERT(!_psp);
// We're done with MSHTML's MatchExactGetIDsOfNames
if (_hinstMSHTML)
{
FreeLibrary(_hinstMSHTML);
}
// Clear any pending or active navigation contexts
_SetPendingNavigateContext(NULL, NULL);
_ActivatePendingNavigateContext();
// Close the browse context and release it.
if (_phlbc)
{
IHlinkBrowseContext * phlbc = _phlbc;
phlbc->AddRef();
SetBrowseContext(NULL);
phlbc->Close(0);
phlbc->Release();
}
SetOwner(NULL);
if (m_pszFrameName)
{
LocalFree(m_pszFrameName);
m_pszFrameName = NULL;
}
if (m_pszFrameSrc)
{
LocalFree(m_pszFrameSrc);
m_pszFrameSrc = NULL;
}
if (_pITI)
_pITI->Release();
if (_pbs)
_pbs->Release();
if (_pwszShortcutPath)
{
LocalFree(_pwszShortcutPath);
_pwszShortcutPath = NULL;
}
if (_pwszShortcutPathPending)
{
LocalFree(_pwszShortcutPathPending);
_pwszShortcutPathPending = NULL;
}
// Paranoia
_ClearPropertyList();
ASSERT( 0 != s_cIEFrameAuto );
LONG cRef = InterlockedDecrement(&s_cIEFrameAuto);
ASSERT(cRef >= 0 );
if (0 == cRef )
{
//
// we were releasing these guys
// in DllRelease, but to avoid mem
// leaks we need to be more aggressive
// about deleting them.
//
DestroyHdpaHooks();
}
DllRelease();
TraceMsg(TF_SHDLIFE, "dtor CIEFrameAuto %x", this);
}
/* IWebBrowserApp methods */
// Display name of the application
HRESULT CIEFrameAuto::get_Name(BSTR * pbstrName)
{
*pbstrName = LoadBSTR(IDS_NAME);
return *pbstrName ? S_OK : E_OUTOFMEMORY;
}
HRESULT CIEFrameAuto::get_HWND(LONG_PTR *pHWND)
{
*pHWND = HandleToLong(_GetHWND());
return *pHWND ? S_OK : E_FAIL;
}
// Fule filespec of executable, but sample I've seen doesn't give extension
HRESULT CIEFrameAuto::get_FullName(BSTR * pbstrFullName)
{
// HACK: This is also the way to tell it to update the pidl in the window list.
if (_pbs) //Make sure we have a IBrowserService.
_pbs->UpdateWindowList();
TCHAR szPath[MAX_PATH];
if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) > 0)
{
*pbstrFullName = SysAllocStringT(szPath);
return *pbstrFullName ? S_OK : E_OUTOFMEMORY;
}
*pbstrFullName = NULL;
return E_FAIL;
}
// Path to the executable
STDMETHODIMP CIEFrameAuto::get_Path(BSTR * pbstrPath)
{
TCHAR szPath[MAX_PATH];
if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) > 0)
{
*PathFindFileName(szPath) = TEXT('\0');
*pbstrPath = SysAllocStringT(szPath);
return *pbstrPath ? S_OK : E_OUTOFMEMORY;
}
*pbstrPath = NULL;
return E_FAIL;
}
HRESULT CIEFrameAuto::get_Application(IDispatch **ppDisp)
{
return QueryInterface(IID_PPV_ARG(IDispatch, ppDisp));
}
HRESULT CIEFrameAuto::get_Parent(IDispatch **ppDisp)
{
return QueryInterface(IID_PPV_ARG(IDispatch, ppDisp));
}
HRESULT CIEFrameAuto::get_Left(long * pl)
{
ASSERT(pl);
HRESULT hr;
HWND hwnd = _GetHWND();
if (hwnd)
{
RECT rc;
GetWindowRect(hwnd, &rc);
*pl = rc.left;
hr = S_OK;
}
else
{
*pl = 0;
hr = S_FALSE;
}
return hr;
}
HRESULT CIEFrameAuto::put_Left(long Left)
{
RECT rc;
if (_pbs)
_pbs->SetFlags(BSF_UISETBYAUTOMATION, BSF_UISETBYAUTOMATION);
HWND hwnd = _GetHWND();
if (hwnd)
{
GetWindowRect(hwnd, &rc);
SetWindowPos(hwnd, NULL, Left, rc.top, 0, 0, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE);
}
return S_OK;
}
HRESULT CIEFrameAuto::get_Top(long * pl)
{
ASSERT(pl);
HRESULT hr;
HWND hwnd = _GetHWND();
if (hwnd)
{
RECT rc;
GetWindowRect(hwnd, &rc);
*pl = rc.top;
hr = S_OK;
}
else
{
*pl = 0;
hr = S_FALSE;
}
return hr;
}
HRESULT CIEFrameAuto::put_Top(long Top)
{
RECT rc;
if (_pbs)
_pbs->SetFlags(BSF_UISETBYAUTOMATION, BSF_UISETBYAUTOMATION);
HWND hwnd = _GetHWND();
if (hwnd)
{
GetWindowRect(hwnd, &rc);
SetWindowPos(hwnd, NULL, rc.left, Top, 0, 0, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE);
}
return S_OK;
}
HRESULT CIEFrameAuto::get_Width(long * pl)
{
ASSERT(pl);
HRESULT hr;
HWND hwnd = _GetHWND();
if (hwnd)
{
RECT rc;
GetWindowRect(hwnd, &rc);
*pl = rc.right - rc.left;
hr = S_OK;
}
else
{
*pl = 0;
hr = S_FALSE;
}
return hr;
}
HRESULT CIEFrameAuto::put_Width(long Width)
{
if (_pbs)
_pbs->SetFlags(BSF_UISETBYAUTOMATION, BSF_UISETBYAUTOMATION);
HWND hwnd = _GetHWND();
if (hwnd)
{
RECT rc;
GetWindowRect(hwnd, &rc);
SetWindowPos(hwnd, NULL, 0, 0, Width, rc.bottom-rc.top, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE);
}
return S_OK;
}
HRESULT CIEFrameAuto::get_Height(long * pl)
{
ASSERT(pl);
HRESULT hr;
HWND hwnd = _GetHWND();
if (hwnd)
{
RECT rc;
GetWindowRect(hwnd, &rc);
*pl = rc.bottom - rc.top;
hr = S_OK;
}
else
{
*pl = 0;
hr = S_FALSE;
}
return hr;
}
HRESULT CIEFrameAuto::put_Height(long Height)
{
if (_pbs)
_pbs->SetFlags(BSF_UISETBYAUTOMATION, BSF_UISETBYAUTOMATION);
HWND hwnd = _GetHWND();
if (hwnd)
{
RECT rc;
GetWindowRect(hwnd, &rc);
SetWindowPos(hwnd, NULL, 0, 0, rc.right-rc.left, Height, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE);
}
return S_OK;
}
HRESULT CIEFrameAuto::put_Titlebar(BOOL fValue)
{
HWND hwnd;
HRESULT hres = get_HWND((LONG_PTR*)&hwnd);
if (SUCCEEDED(hres))
{
DWORD dwVal = GetWindowLong(hwnd, GWL_STYLE);
if (fValue)
dwVal |= WS_CAPTION;
else
dwVal &= ~WS_CAPTION;
if (SetWindowLong(hwnd, GWL_STYLE, dwVal))
{
// We need to do a SetWindowPos in order for the style changes to take effect
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
else
hres = E_FAIL;
}
return hres;
}
HRESULT CIEFrameAuto::get_Visible(VARIANT_BOOL * pBool)
{
HWND hwnd = _GetHWND();
*pBool = hwnd ? TO_VARIANT_BOOL(IsWindowVisible(hwnd)) : VARIANT_FALSE;
return S_OK;
}
HRESULT CIEFrameAuto::put_Visible(VARIANT_BOOL Value)
{
HWND hwnd = _GetHWND();
if (hwnd)
{
::ShowWindow(hwnd, Value? SW_SHOW : SW_HIDE);
if (Value)
::SetForegroundWindow(::GetLastActivePopup(hwnd));
FireEvent_OnAdornment(_GetOuter(), DISPID_ONVISIBLE, Value);
}
return S_OK;
}
HRESULT CIEFrameAuto::get_Document(IDispatch **ppDisp)
{
HRESULT hres = E_FAIL;
IShellView * psv = NULL;
*ppDisp = NULL;
if (_psb)
{
hres = _psb->QueryActiveShellView(&psv);
if (FAILED(hres))
{
CComVariant cvarUnk;
hres = _pmsc->Exec(&CGID_ShellDocView, SHDVID_GETPENDINGOBJECT, 0, NULL, &cvarUnk);
if (SUCCEEDED(hres))
{
if ((VT_UNKNOWN == V_VT(&cvarUnk)) && V_UNKNOWN(&cvarUnk))
{
hres = cvarUnk.punkVal->QueryInterface(IID_IShellView, (void**)&psv);
}
else
{
hres = E_FAIL;
}
}
}
if (psv)
{
IDispatch * pDisp;
hres = SafeGetItemObject(psv, SVGIO_BACKGROUND, IID_PPV_ARG(IDispatch, &pDisp));
if (SUCCEEDED(hres))
{
// (scotrobe 01/14/2000): We need to QI for IHTMLDocument2 to support
// bad apps (e.g., HotMetal Pro) that cast the IDispatch to IHTMLDocument2.
// Casting like this used to work because the object returned from
// SafeGetItemObject() used to implement IHTMLDocument2. Now, it delegates
// that implementation to another object. If the QI for IHTMLDocument2 fails, '
// then the object is not MSHTML. In that case, we just return the
// IDispatch that was returned from SafeGetItemObject().
//
IHTMLDocument2 * pDocument;
HRESULT hr = pDisp->QueryInterface(IID_PPV_ARG(IHTMLDocument2, &pDocument));
if (SUCCEEDED(hr))
{
*ppDisp = pDocument;
pDisp->Release();
}
else // Non-html document
{
*ppDisp = pDisp; // Don't release pDisp
}
}
psv->Release();
}
}
return hres;
}
HRESULT CIEFrameAuto::get_Busy(VARIANT_BOOL *pBool)
{
if (_pbs == NULL)
{
TraceMsg(DM_WARNING, "CIEA::get_Busy called _pbs==NULL");
return E_FAIL;
}
BNSTATE bnstate;
HRESULT hres = _pbs->GetNavigateState(&bnstate);
if (SUCCEEDED(hres))
{
*pBool = TO_VARIANT_BOOL(bnstate != BNS_NORMAL);
hres = S_OK;
}
return hres;
}
// MSDN97 keeps asking for a location until it gets success, so it
// hangs if we fail. Make sure no code paths return early from here...
//
HRESULT CIEFrameAuto::_get_Location(BSTR * pbstr, UINT uFlags)
{
if (_pbs)
{
LPITEMIDLIST pidl;
HRESULT hres = _pbs->GetPidl(&pidl);
if (SUCCEEDED(hres))
{
WCHAR wszTitle[MAX_URL_STRING];
hres = _pbs->IEGetDisplayName(pidl, wszTitle, uFlags);
ILFree(pidl);
if (SUCCEEDED(hres))
{
//
// if url is a pluggable protocol, get the real url by
// chopping of the base url
//
WCHAR *pchUrl = StrChrW(wszTitle, L'\1');
if (pchUrl)
*pchUrl = 0;
//
// if there is already an URL then we just use it
//
if ((uFlags & SHGDN_FORPARSING) && !PathIsURLW(wszTitle))
{
int nScheme;
//
// otherwise we need to treat it as if it were new
// and make sure it is a parseable URL.
//
DWORD cchTitle = ARRAYSIZE(wszTitle);
ParseURLFromOutsideSourceW(wszTitle, wszTitle, &cchTitle, NULL);
// BUG FIX #12221:
// ParseURLFromOutsideSource() was called to turn a file path into
// a fully qualified FILE URL. If the URL was of any other type
// (non-URL sections of the name space), then we want to NULL out the
// string to indicate that it's invalid. We don't return E_FAIL because
// HotDog Pro appears to have problems with that as indicated by the comment
// below.
nScheme = GetUrlSchemeW(wszTitle);
if (URL_SCHEME_FILE != nScheme)
wszTitle[0] = TEXT('\0');
}
*pbstr = SysAllocString(wszTitle);
return *pbstr ? S_OK : E_OUTOFMEMORY;
}
}
}
// If we're here, the TLGetPidl call failed. This can happen if get_LocationName
// or get_LocationURL is called before the first navigate is complete. HotDog Pro does
// this, and was failing with E_FAIL. Now we'll just return an empty string with S_FALSE.
//
// Also MSDN97 hangs (NT5 bug 232126) if we return failure. Guess there hosed on low
// memory situations...
//
*pbstr = SysAllocString(L"");
return *pbstr ? S_FALSE : E_OUTOFMEMORY;
}
HRESULT CIEFrameAuto::get_LocationName(BSTR * pbstrLocationName)
{
return _get_Location(pbstrLocationName, SHGDN_NORMAL);
}
HRESULT CIEFrameAuto::get_LocationURL(BSTR * pbstrLocationURL)
{
return _get_Location(pbstrLocationURL, SHGDN_FORPARSING);
}
HRESULT CIEFrameAuto::Quit()
{
// try to close it down...
_fQuitInProgress = 1;
HWND hwnd = _GetHWND();
if (hwnd)
PostMessage(hwnd, WM_CLOSE, 0, 0);
return S_OK;
}
HRESULT CIEFrameAuto::ClientToWindow(int *pcx, int *pcy)
{
if (_pbs==NULL)
{
TraceMsg(DM_WARNING, "CIEA::ClientToWindow called _pbs==NULL");
return E_FAIL;
}
HWND hwnd;
RECT rc;
BOOL b;
rc.left = 0;
rc.right = *pcx;
rc.top = 0;
rc.bottom = *pcy;
_pbs->IsControlWindowShown(FCW_MENUBAR, &b);
HWND hwnd2 = _GetHWND();
if (hwnd2)
AdjustWindowRect(&rc, GetWindowLong(hwnd2, GWL_STYLE), b);
*pcx = rc.right-rc.left;
*pcy = rc.bottom-rc.top;
_pbs->IsControlWindowShown(FCW_STATUS, &b);
if (b)
{
_psb->GetControlWindow(FCW_STATUS, &hwnd);
if (hwnd)
{
GetWindowRect(hwnd, &rc);
*pcy += rc.bottom-rc.top;
}
}
_pbs->IsControlWindowShown(FCW_INTERNETBAR, &b);
if (b)
{
_psb->GetControlWindow(FCW_INTERNETBAR, &hwnd);
if (hwnd)
{
GetWindowRect(hwnd, &rc);
*pcy += rc.bottom-rc.top;
}
}
// add in 4 pixels for 3d borders, but don't include scrollbars
// 'cause Netscape doesn't
*pcy += 2*GetSystemMetrics(SM_CYEDGE);
*pcx += 2*GetSystemMetrics(SM_CXEDGE);
return S_OK;
}
void CIEFrameAuto::_ClearPropertyList()
{
CIEFrameAutoProp *pprop = _pProps;
_pProps = NULL; // cleared out early...
CIEFrameAutoProp *ppropNext;
while (pprop)
{
ppropNext = pprop->Next();
delete pprop;
pprop = ppropNext;
}
}
HRESULT CIEFrameAuto::PutProperty(BSTR bstrProperty, VARIANT vtValue)
{
if (!bstrProperty)
{
TraceMsg(TF_ERROR, "CIEFrameAuto::PutProperty() - bstrProperty is NULL!");
return E_INVALIDARG;
}
#ifdef DEBUG
// Check if this BSTR is a valid BSTR
SA_BSTR* psstr = (SA_BSTR*)((LPBYTE)bstrProperty - sizeof(ULONG));
ASSERT(psstr->cb == lstrlenW(psstr->wsz)*sizeof(WCHAR));
#endif
HRESULT hres;
CIEFrameAutoProp *pprop = _pProps;
while (pprop && !pprop->IsOurProp(bstrProperty))
pprop=pprop->Next();
if (!pprop)
{
pprop = new CIEFrameAutoProp;
if (!pprop)
return E_OUTOFMEMORY;
if (FAILED(hres=pprop->Initialize(bstrProperty)))
{
delete pprop;
return hres;
}
pprop->_next = _pProps;
_pProps = pprop;
}
hres = pprop->SetValue(&vtValue, this);
// We should now tell anyone who is listening about the change...
FireEvent_DoInvokeBstr(_GetOuter(), DISPID_PROPERTYCHANGE, bstrProperty);
return hres;
}
HRESULT CIEFrameAuto::GetProperty(BSTR bstrProperty, VARIANT * pvtValue)
{
if (!bstrProperty || !pvtValue)
return E_INVALIDARG;
VariantInit(pvtValue);
CIEFrameAutoProp *pprop = _pProps;
while (pprop && !pprop->IsOurProp(bstrProperty))
pprop = pprop->Next();
if (pprop)
{
return pprop->CopyValue(pvtValue);
}
// Did not find property return empty...
// Not there. Probably not worth an error...
return S_OK;
}
extern HRESULT TargetQueryService(IUnknown *punk, REFIID riid, void **ppvObj);
//+-------------------------------------------------------------------------
//
// Method : CIEFrameAuto::Navigate
//
// Interface : IWebBrowser
//
//--------------------------------------------------------------------------
HRESULT CIEFrameAuto::Navigate(BSTR URL,
VARIANT * Flags,
VARIANT * TargetFrameName,
VARIANT * PostData,
VARIANT * Headers)
{
return _NavigateHelper(URL, Flags, TargetFrameName, PostData, Headers);
}
//+-------------------------------------------------------------------------
//
// Method : CIEFrameAuto::NavigateWithBindCtx
//
// Interface : IWebBrowserPriv
//
//--------------------------------------------------------------------------
HRESULT CIEFrameAuto::NavigateWithBindCtx(VARIANT FAR * pvarUrl,
VARIANT FAR * pvarFlags,
VARIANT FAR * pvarTargetFrameName,
VARIANT FAR * pvarPostData,
VARIANT FAR * pvarHeaders,
IBindCtx * pBindCtx,
BSTR bstrLocation)
{
return _NavigateHelper(V_BSTR(pvarUrl),
pvarFlags,
pvarTargetFrameName,
pvarPostData,
pvarHeaders,
pBindCtx,
bstrLocation);
}
//+-------------------------------------------------------------------------
//
// Method : CIEFrameAuto::NavigateWithBC
//
// Interface : IWebBrowserPriv
//
//--------------------------------------------------------------------------
HRESULT
CIEFrameAuto::OnClose()
{
// Clear any pending or active navigation contexts
//
_SetPendingNavigateContext(NULL, NULL);
_ActivatePendingNavigateContext();
return S_OK;
}
//+-------------------------------------------------------------------------
//
// Method : CIEFrameAuto::_NavigateHelper
//
//--------------------------------------------------------------------------
HRESULT
CIEFrameAuto::_NavigateHelper(BSTR URL,
VARIANT * Flags,
VARIANT * TargetFrameName,
VARIANT * PostData,
VARIANT * Headers,
IBindCtx * pNavBindCtx, /* = NULL */
BSTR bstrLocation /* = NULL */)
{
if (NULL == _pbs)
{
TraceMsg(DM_WARNING, "CIEA::Navigate called _pbs==NULL");
return E_FAIL;
}
if (NULL == URL)
{
TraceMsg(TF_SHDAUTO, "Shell automation: CIEFrameAuto::Navigate <NULL> called");
return(_BrowseObject(PIDL_NOTHING, 0));
}
// Special hack for AOL: They send us the following "url" as a null navigate.
// Then they immediately follow it with the url for the new window. That second
// navigate is failing with RPC_E_CALL_REJECTED because of our message filter.
// We fix the new window case by special casing this URL and returning S_FALSE.
// This url will not likely ever be seen in the real world, and if it is typed in,
// will get normalized and canonicalized long before getting here.
//
if (!StrCmpIW(URL, L"x-$home$://null"))
{
return S_FALSE;
}
#ifdef BROWSENEWPROCESS_STRICT // "Nav in new process" has become "Launch in new process", so this is no longer needed
// if we want ALL navigates to be in a separate process, then we need to
// pick off URL navigates for CShellBrowser IShellBrowser implementations
// when we are in the explorer process. We can wait until IShellBrowser::BrowseObject,
// but then we may lose TargetFrameName etc...
//
if (IsBrowseNewProcessAndExplorer() && !IsShellUrl(URL, TRUE))
{
}
#endif
HRESULT hres;
LPITEMIDLIST pidl = NULL;
LPBINDCTX pBindCtx = NULL;
DWORD cbPostData = 0;
LPCWSTR pwzHeaders = NULL;
DWORD dwInFlags = 0;
DWORD dwFlags = 0;
LPCBYTE pPostData = NULL;
DWORD grBindFlags = 0;
SAFEARRAY * pPostDataArray = NULL;
BOOL fOpenWithFrameName = FALSE;
CStubBindStatusCallback * pStubCallback = NULL;
// get target frame name out of variant
LPCWSTR pwzTargetFrameName = NULL;
LPCWSTR pwzUnprefixedTargetFrameName = NULL;
hres = E_FAIL;
TraceMsg(TF_SHDAUTO, "Shell automation: CIEFrameAuto::Navigate %s called", URL);
if (TargetFrameName)
{
if ((VT_BSTR | VT_BYREF) == TargetFrameName->vt)
pwzTargetFrameName = *TargetFrameName->pbstrVal;
else if (VT_BSTR == TargetFrameName->vt)
pwzTargetFrameName = TargetFrameName->bstrVal;
}
// if a target name was specified, send the navigation to the appropriate target
// NOTE: for compatibility we can't change the meaning of target here
// thus we don't attempt to find alias
if ((pwzTargetFrameName && pwzTargetFrameName[0]))
{
LPTARGETFRAME2 pOurTargetFrame = NULL;
IUnknown *punkTargetFrame;
IWebBrowserApp * pIWebBrowserApp;
BOOL fHandled = FALSE;
// see if there is an existing frame with the specified target name
// NOTE: we used docked parameter of _self to force navigation of this
// frame, regardless of whether it is WebBar.
hres = TargetQueryService((IShellBrowser *)this, IID_PPV_ARG(ITargetFrame2, &pOurTargetFrame));
ASSERT(SUCCEEDED(hres));
if (SUCCEEDED(hres))
{
// Workaround for the way Compuserve handles the NewWindow event (window.open)
// They tell the new instance of the web browser to navigate, but they pass the target frame
// name they received on the NewWindow event. This confuses us because that frame name
// has the "_[number]" prefix.
//
// If the first two characters are "_[", then look for the "]" and reallocate a string
// with everthing after that bracket.
//
if (StrCmpNW(pwzTargetFrameName, L"_[", 2) == 0)
{
pwzUnprefixedTargetFrameName = StrChrW(pwzTargetFrameName, L']');
if (pwzUnprefixedTargetFrameName)
{
pwzUnprefixedTargetFrameName++;
pwzTargetFrameName = SysAllocString(pwzUnprefixedTargetFrameName);
if (!pwzTargetFrameName)
{
hres = E_OUTOFMEMORY;
goto exit;
}
}
}
hres = pOurTargetFrame->FindFrame(pwzTargetFrameName,
FINDFRAME_JUSTTESTEXISTENCE,
&punkTargetFrame);
if (SUCCEEDED(hres) && punkTargetFrame)
{
// yes, we found a frame with that name. QI for the automation
// interface on that frame and call navigate on it.
hres = punkTargetFrame->QueryInterface(IID_PPV_ARG(IWebBrowserApp, &pIWebBrowserApp));
punkTargetFrame->Release();
ASSERT(SUCCEEDED(hres));
if (SUCCEEDED(hres))
{
VARIANT var;
LBSTR::CString strFrame;
VariantInit(&var);
var.vt = VT_BSTR;
var.bstrVal = strFrame;
hres = pIWebBrowserApp->Navigate(URL, Flags, &var, PostData, Headers);
var.bstrVal = NULL;
VariantClearLazy(&var);
pIWebBrowserApp->Release();
fHandled = TRUE;
}
}
else if (SUCCEEDED(hres))
{
//no target found means we need to open a new window
//hres = E_FAIL forces parsing of URL into pidl
//if we have no target frame name, then
// BETA1 hack chrisfra 3/3/97. in BETA 2 TargetFrame2
// interface must support aliasing of targets (even if NULL
// to support links in desktop components as per PM requirements
if (!pwzTargetFrameName || !pwzTargetFrameName[0])
{
ASSERT(_fDesktopComponent());
pwzTargetFrameName = L"_desktop";
}
dwFlags |= HLNF_OPENINNEWWINDOW;
fOpenWithFrameName = TRUE;
hres = E_FAIL;
}
pOurTargetFrame->Release();
if (fHandled)
goto exit;
}
}
if (FAILED(hres))
{
hres = _PidlFromUrlEtc(CP_ACP, (LPCWSTR)URL, bstrLocation, &pidl);
if (FAILED(hres))
goto exit;
}
// to perform the navigation, we either call an internal method
// (_pbs->NavigateToPidl) or an external interface (IHlinkFrame::Navigate),
// depending on what data we need to pass. NavigateToPidl is faster
// and cheaper, but does not allow us to pass headers or post data, just
// the URL! So what we do is call the fast and cheap way if only the URL
// was specified (the 90% case), and if either headers or post data were
// specified then we call the external interface. We have to do a bunch
// of wrapping of parameters in IMonikers and IHlinks and whatnot only to
// unwrap them at the other end, so we won't call this unless we need to.
if (Headers)
{
if ((VT_BSTR | VT_BYREF) == Headers->vt)
{
pwzHeaders = *Headers->pbstrVal;
}
else if (VT_BSTR == Headers->vt)
{
pwzHeaders = Headers->bstrVal;
}
}
//
// HACK: We used to do VT_ARRAY==PostData->vt, which is bogus.
// It is supposed to be VT_ARRAY|VT_UI1==PostData->vt. We can't
// however do it for backward compatibility with AOL and CompuServe.
// Therefore, we do (VT_ARRAY & PostData->vt)
//
if (PostData && (VT_ARRAY & PostData->vt))
{
if (VT_BYREF & PostData->vt)
{
pPostDataArray = *PostData->pparray;
}
else
{
pPostDataArray = PostData->parray;
}
ASSERT(pPostDataArray);
if (pPostDataArray)
{
// lock the array for reading, get pointer to data
hres = SafeArrayAccessData(pPostDataArray, (void**)&pPostData);
if (SUCCEEDED(hres))
{
long nElements = 0;
DWORD dwElemSize;
// get number of elements in array
SafeArrayGetUBound(pPostDataArray,1,(long *) &nElements);
// SafeArrayGetUBound returns zero-based max index, add one to get element count
nElements++;
// get bytes per element
dwElemSize = SafeArrayGetElemsize(pPostDataArray);
// bytes per element should be one if we created this array
ASSERT(dwElemSize == 1);
// calculate total byte count anyway so that we can handle
// safe arrays other people might create with different element sizes
cbPostData = dwElemSize * nElements;
if (0 == cbPostData)
pPostData = NULL;
}
}
}
// convert from automation interface flags (nav*) to
// hyperlinking flags (HLNF_*)
if (Flags)
{
if (Flags->vt == VT_I4)
{
dwInFlags = Flags->lVal;
}
else if (Flags->vt == VT_I2)
{
dwInFlags = Flags->iVal;
}
if ((dwInFlags & navOpenInNewWindow))
{
dwFlags |= HLNF_OPENINNEWWINDOW;
}
if (dwInFlags & navNoHistory)
{
dwFlags |= HLNF_CREATENOHISTORY;
}
if (dwInFlags & navNoReadFromCache)
{
grBindFlags |= BINDF_RESYNCHRONIZE | BINDF_PRAGMA_NO_CACHE;
}
if (dwInFlags & navNoWriteToCache)
{
grBindFlags |= BINDF_NOWRITECACHE;
}
if (dwInFlags & navHyperlink)
{
grBindFlags |= BINDF_HYPERLINK;
}
if (dwInFlags & navEnforceRestricted)
{
grBindFlags |= BINDF_ENFORCERESTRICTED;
}
// Should call IsBrowserFrameOptionsPidlSet() instead. Some URL delegate
// NSEs may or may not want this feature.
if (IsURLChild(pidl, TRUE) && (dwInFlags & navAllowAutosearch))
{
dwFlags |= HLNF_ALLOW_AUTONAVIGATE;
}
}
// if we have either headers or post data or need to open the page in a
// new window or pass HLNF_CREATENOHISTORY, we have to do the navigation
// the hard way (through IHlinkFrame::Navigate) -- here we have to do
// a bunch of wrapping of parameters into COM objects that IHlinkFrame::
// Navigate wants.
if (pwzHeaders || pPostData || dwFlags || grBindFlags)
{
// Check to see if this frame is offline.
// This is the same as doing a get_Offline
VARIANT_BOOL vtbFrameIsOffline = m_bOffline ? VARIANT_TRUE : VARIANT_FALSE;
VARIANT_BOOL vtbFrameIsSilent = m_bSilent ? VARIANT_TRUE : VARIANT_FALSE;
// make a "stub" bind status callback to hold that data and pass it
// to the URL moniker when requested
hres = CStubBindStatusCallback_Create(pwzHeaders,pPostData,cbPostData,
vtbFrameIsOffline, vtbFrameIsSilent,
TRUE, grBindFlags, &pStubCallback);
if (FAILED(hres))
goto exit;
// get the canonicalized name back out of the pidl. Note this is
// different than the URL passed in... it has been auto-protocol-ized,
// canonicalized and generally munged in the process of creating the pidl,
// which is what we want to use.
// need +3. +2 for iegetdisplayname call inside failed statment below, and +1 for movememory further below
WCHAR wszPath[MAX_URL_STRING+3]; // note stomping below if changed to dynalloc
hres = _pbs->IEGetDisplayName(pidl, wszPath, SHGDN_FORPARSING);
if (FAILED(hres))
{
// On Win9x, IEGetDisplayName(SHGDN_FORPARSING) will return NOT_IMPLEMENTED
// for \\servername (but not \\servername\share)
// We need to work around this.
DWORD ccPath = ARRAYSIZE(wszPath);
if (SUCCEEDED(PathCreateFromUrl(URL, wszPath, &ccPath, 0))
&& *wszPath==L'\\'
&& *(wszPath+1)==L'\\')
{
hres = _pbs->IEGetDisplayName(pidl, wszPath + 2, SHGDN_FORADDRESSBAR); // assumes MAX_URL_STRING size for the string
}
}
if (FAILED(hres))
{
TraceMsg(DM_ERROR, "CIEFrameAuto::Navigate _pbs->IEGetDisplayName failed %x", hres);
goto exit;
}
WCHAR *pwzLocation = (WCHAR *)UrlGetLocationW(wszPath);
if (pwzLocation)
{
// NOTE: we allocated an extra char, just so we could do the following
MoveMemory(pwzLocation+1, pwzLocation, (lstrlenW(pwzLocation)+1)*sizeof(WCHAR));
*pwzLocation++ = TEXT('\0'); // we own wszPath, so we can do this.
}
if (!pNavBindCtx) // A bind ctx was not passed in.
{
// Create a bind context to pass to IHlinkFrame::Navigate
//
hres = CreateBindCtx(0, &pBindCtx);
if (FAILED(hres))
goto exit;
}
else
{
pBindCtx = pNavBindCtx;
pBindCtx->AddRef();
}
// We have either post data or headers (or we need to open
// in a new window) to pass in addition to URL.
// Call IHlinkFrame::Navigate to do the navigation
//
hres = NavigateHack(dwFlags,
pBindCtx,
pStubCallback,
fOpenWithFrameName ? pwzTargetFrameName:NULL,
wszPath,
pwzLocation);
}
else
{
ASSERT(dwFlags == 0);
if (pNavBindCtx)
{
_SetPendingNavigateContext(pNavBindCtx, NULL);
}
//
// NOTES: We used to call _pbs->NavigatePidl (in IE3.0), now we call
// _psb->BrowseObject, so that we ALWAYS hit that code path.
//
hres = _BrowseObject(pidl, SBSP_SAMEBROWSER|SBSP_ABSOLUTE);
}
exit:
// clean up
if (pPostDataArray)
{
// done reading from array, unlock it
SafeArrayUnaccessData(pPostDataArray);
}
// If pwzUnprefixedTargetFrameName is non-null, then we allocated and set our own
// pwzTargetFrameName.
//
if (pwzUnprefixedTargetFrameName && pwzTargetFrameName)
{
SysFreeString((BSTR) pwzTargetFrameName);
}
ATOMICRELEASE(pStubCallback);
ATOMICRELEASE(pBindCtx);
Pidl_Set(&pidl, NULL);
return hres;
}
//
// Parameters:
// pvaClsid Specifies the bar to be shown/hide
// pvaShow Specifies whether or not we should show or hide (default is show)
// pvaSize Specifies the size (optional)
// HACK: really hoaky nCmdExecOpt overloading...
//
HRESULT CIEFrameAuto::ShowBrowserBar(VARIANT * pvaClsid, VARIANT *pvaShow, VARIANT *pvaSize)
{
// Use this convenient, marshalable method to show or hide the Address (URL) band, the tool band,
// or the link band.
//
if (pvaShow && pvaShow->vt == VT_EMPTY)
pvaShow = NULL;
if (pvaShow && pvaShow->vt != VT_BOOL)
return DISP_E_TYPEMISMATCH;
if (pvaClsid->vt == VT_I2
&& (pvaClsid->iVal == FCW_ADDRESSBAR
|| pvaClsid->iVal == FCW_TOOLBAND
|| pvaClsid->iVal == FCW_LINKSBAR))
{
return IUnknown_Exec(_pbs, &CGID_Explorer, SBCMDID_SHOWCONTROL,
MAKELONG(pvaClsid->iVal, pvaShow ? pvaShow->boolVal : 1), NULL, NULL);
}
else {
return IUnknown_Exec(_pbs, &CGID_ShellDocView, SHDVID_SHOWBROWSERBAR,
pvaShow ? pvaShow->boolVal : 1, pvaClsid, NULL);
}
}
HRESULT CIEFrameAuto::Navigate2(VARIANT * pvURL, VARIANT * pFlags, VARIANT * pTargetFrameName, VARIANT * pPostData, VARIANT * pHeaders)
{
HRESULT hr = E_INVALIDARG;
if (pFlags && ((WORD)(VT_I4) == pFlags->vt) && (pFlags->lVal == navBrowserBar))
{
hr = IUnknown_Exec(_pbs, &CGID_ShellDocView, SHDVID_NAVIGATEBB, 0, pvURL, NULL);
}
else if (!pvURL)
{
hr = Navigate(NULL, NULL, NULL, NULL, NULL);
}
else
{
LPCWSTR pszURL = VariantToStrCast(pvURL);
if (pszURL)
{
hr = Navigate((BSTR)pszURL, pFlags, pTargetFrameName, pPostData, pHeaders);
}
else
{
LPITEMIDLIST pidl = VariantToIDList(pvURL);
if (pidl)
{
hr = _BrowseObject(pidl, SBSP_SAMEBROWSER | SBSP_ABSOLUTE);
ILFree(pidl);
}
}
}
return hr;
}
HRESULT CIEFrameAuto::GoBack()
{
HRESULT hr;
IWebBrowser *pwb;
if (!IsSameObject(_psb, _psbFrameTop) && _psbFrameTop)
{
hr = IUnknown_QueryService(_psbFrameTop, IID_ITargetFrame2, IID_PPV_ARG(IWebBrowser, &pwb));
if (pwb)
{
hr = pwb->GoBack();
pwb->Release();
}
else
hr = E_FAIL;
}
else
hr = _BrowseObject(NULL, SBSP_SAMEBROWSER|SBSP_NAVIGATEBACK);
return hr;
}
HRESULT CIEFrameAuto::GoForward()
{
HRESULT hr;
IWebBrowser *pwb;
if (!IsSameObject(_psb, _psbFrameTop) && _psbFrameTop)
{
hr = IUnknown_QueryService(_psbFrameTop, IID_ITargetFrame2, IID_PPV_ARG(IWebBrowser, &pwb));
if (pwb)
{
hr = pwb->GoForward();
pwb->Release();
}
else
hr = E_FAIL;
}
else
hr = _BrowseObject(NULL, SBSP_SAMEBROWSER|SBSP_NAVIGATEFORWARD);
return hr;
}
HRESULT CIEFrameAuto::_GoStdLocation(DWORD dwWhich)
{
TraceMsg(TF_SHDAUTO, "Shell automation: CIEFrameAuto:GoHome called");
HRESULT hres;
LPITEMIDLIST pidl = NULL;
HWND hwnd = _GetHWND();
if (hwnd)
{
hres = SHDGetPageLocation(hwnd, dwWhich, NULL, 0, &pidl);
if (SUCCEEDED(hres)) {
//
// NOTES: We used to call _pbs->NavigatePidl (in IE3.0), now we call
// _psb->BrowseObject, so that we ALWAYS hit that code path.
//
hres = _BrowseObject(pidl, SBSP_SAMEBROWSER|SBSP_ABSOLUTE);
ILFree(pidl);
}
}
else
{
hres = S_FALSE;
}
return hres;
}
HRESULT CIEFrameAuto::GoHome()
{
return _GoStdLocation(IDP_START);
}
HRESULT CIEFrameAuto::GoSearch()
{
return _GoStdLocation(IDP_SEARCH);
}
HRESULT CIEFrameAuto::Stop()
{
//
// Calling _CancelPendingNavigation() is not enough here because
// it does not stop the on-going navigation in the current page.
// Exec(NULL, OLECMDID_STOP) will cancel pending navigation AND
// stop the on-going navigation.
//
if (_pmsc) {
return _pmsc->Exec(NULL, OLECMDID_STOP, 0, NULL, NULL);
}
return(E_UNEXPECTED);
}
HRESULT CIEFrameAuto::Refresh()
{
VARIANT v = {0};
v.vt = VT_I4;
v.lVal = OLECMDIDF_REFRESH_NO_CACHE;
return Refresh2(&v);
}
HRESULT CIEFrameAuto::Refresh2(VARIANT * Level)
{
HRESULT hres = E_FAIL;
IShellView *psv;
if (_psb && SUCCEEDED(hres = _psb->QueryActiveShellView(&psv)) && psv)
{
hres = IUnknown_Exec(psv, NULL, OLECMDID_REFRESH, OLECMDEXECOPT_PROMPTUSER, Level, NULL);
psv->Release();
}
return hres;
}
STDMETHODIMP CIEFrameAuto::get_Container(IDispatch **ppDisp)
{
*ppDisp = NULL;
return NOERROR;
}
STDMETHODIMP CIEFrameAuto::get_FullScreen(VARIANT_BOOL * pBool)
{
HRESULT hres;
BOOL bValue;
if (_pbs==NULL) {
TraceMsg(DM_WARNING, "CIEA::get_FullScreen called _pbs==NULL");
return E_FAIL;
}
// Put the processing of this in the main Frame class
bValue = (BOOL)*pBool;
hres = _pbs->IsControlWindowShown((UINT)-1, &bValue);
*pBool = TO_VARIANT_BOOL(bValue);
return hres;
}
STDMETHODIMP CIEFrameAuto::put_FullScreen(VARIANT_BOOL Bool)
{
HRESULT hres;
if (_pbs==NULL) {
TraceMsg(DM_WARNING, "CIEA::put_FullScreen called _pbs==NULL");
return E_FAIL;
}
_pbs->SetFlags(BSF_UISETBYAUTOMATION, BSF_UISETBYAUTOMATION);
// Put the processing of this in the main Frame class
hres = _pbs->ShowControlWindow((UINT)-1, (BOOL)Bool);
FireEvent_OnAdornment(_GetOuter(), DISPID_ONFULLSCREEN, Bool);
return(hres);
}
STDMETHODIMP CIEFrameAuto::get_StatusBar(VARIANT_BOOL * pBool)
{
HRESULT hres;
BOOL bValue;
if (!pBool)
return E_INVALIDARG;
if (_pbs==NULL) {
TraceMsg(DM_WARNING, "CIEA::get_StatusBar called _pbs==NULL");
return E_FAIL;
}
// Put the processing of this in the main Frame class
bValue = (BOOL)*pBool;
hres = _pbs->IsControlWindowShown(FCW_STATUS, &bValue);
*pBool = TO_VARIANT_BOOL(bValue);
return hres;
}
STDMETHODIMP CIEFrameAuto::put_StatusBar(VARIANT_BOOL Bool)
{
HRESULT hres;
if (_pbs==NULL) {
TraceMsg(DM_WARNING, "CIEA::put_StatusBar called _pbs==NULL");
return E_FAIL;
}
_pbs->SetFlags(BSF_UISETBYAUTOMATION, BSF_UISETBYAUTOMATION);
hres = _pbs->ShowControlWindow(FCW_STATUS, (BOOL)Bool);
FireEvent_OnAdornment(_GetOuter(), DISPID_ONSTATUSBAR, Bool);
return(hres);
}
STDMETHODIMP CIEFrameAuto::get_StatusText(BSTR * pbstr)
{
HRESULT hr = E_FAIL;
*pbstr = NULL; // clear out in case of error...
if (_pbs)
{
IShellBrowser *psb;
hr = _pbs->QueryInterface(IID_PPV_ARG(IShellBrowser, &psb));
if (SUCCEEDED(hr))
{
LRESULT ret;
hr = psb->SendControlMsg(FCW_STATUS, SB_GETTEXTLENGTH, 0, 0, &ret);
if (SUCCEEDED(hr))
{
ret++; // #246956: We need to make 2 extra spaces for the end
*pbstr = SysAllocStringLen(NULL, LOWORD(ret)+1); // ret doesn't include NULL in count
if (*pbstr)
{
hr = psb->SendControlMsg(FCW_STATUS, SB_GETTEXTW, 0, (LPARAM)(*pbstr), &ret);
if (FAILED(hr))
{
SysFreeString(*pbstr);
*pbstr = NULL;
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
psb->Release();
}
}
return hr;
}
STDMETHODIMP CIEFrameAuto::put_StatusText(BSTR bstr)
{
if (_pbs==NULL)
{
TraceMsg(DM_WARNING, "CIEA::put_StatusText called _pbs==NULL");
return E_FAIL;
}
IShellBrowser *psb;
HRESULT hres = _pbs->QueryInterface(IID_PPV_ARG(IShellBrowser, &psb));
if (SUCCEEDED(hres))
{
hres = psb->SendControlMsg(FCW_STATUS, SB_SETTEXTW, 0, (LPARAM)bstr, NULL);
psb->Release();
}
return hres;
}
STDMETHODIMP CIEFrameAuto::get_ToolBar(int * pBool)
{
if (_pbs==NULL) {
TraceMsg(DM_WARNING, "CIEA::get_ToolBar called _pbs==NULL");
return E_FAIL;
}
// Put the processing of this in the main Frame class
BOOL fShown;
HRESULT hres;
*pBool = 0;
if (SUCCEEDED(hres = _pbs->IsControlWindowShown(FCW_INTERNETBAR, &fShown)) && fShown)
*pBool = 1;
// Don't user hres of next call as this will fail on IE3 which does not
// have a FCW_TOOLBAR control
else if (SUCCEEDED(_pbs->IsControlWindowShown(FCW_TOOLBAR, &fShown)) && fShown)
*pBool = 2;
return hres;
}
STDMETHODIMP CIEFrameAuto::put_ToolBar(int Bool)
{
HRESULT hres;
if (_pbs==NULL) {
TraceMsg(DM_WARNING, "CIEA::put_Toolbar called _pbs==NULL");
return E_FAIL;
}
_pbs->SetFlags(BSF_UISETBYAUTOMATION, BSF_UISETBYAUTOMATION);
// Put the processing of this in the main Frame class
_pbs->ShowControlWindow(FCW_TOOLBAR, (Bool == 2));
hres = _pbs->ShowControlWindow(FCW_INTERNETBAR, ((Bool==1)||(Bool == VARIANT_TRUE)));
FireEvent_OnAdornment(_GetOuter(), DISPID_ONTOOLBAR, Bool);
return(hres);
}
STDMETHODIMP CIEFrameAuto::get_MenuBar(THIS_ VARIANT_BOOL * pbool)
{
BOOL bValue;
HRESULT hres;
if (_pbs==NULL) {
TraceMsg(DM_WARNING, "CIEA::get_MenuBar called _pbs==NULL");
return E_FAIL;
}
if (pbool==NULL)
return E_INVALIDARG;
// Put the processing of this in the main Frame class
bValue = (BOOL)*pbool;
hres = _pbs->IsControlWindowShown(FCW_MENUBAR, &bValue);
*pbool = TO_VARIANT_BOOL(bValue);
return hres;
}
STDMETHODIMP CIEFrameAuto::put_MenuBar(THIS_ VARIANT_BOOL mybool)
{
HRESULT hres;
if (_pbs==NULL) {
TraceMsg(DM_WARNING, "CIEA::put_MenuBar called _pbs==NULL");
return E_FAIL;
}
_pbs->SetFlags(BSF_UISETBYAUTOMATION, BSF_UISETBYAUTOMATION);
hres = _pbs->ShowControlWindow(FCW_MENUBAR, (BOOL)mybool);
FireEvent_OnAdornment(_GetOuter(), DISPID_ONMENUBAR, mybool);
return(hres);
}
//
// IWebBrowser2
//
HRESULT CIEFrameAuto::QueryStatusWB(OLECMDID cmdID, OLECMDF * pcmdf)
{
if (_pmsc)
{
OLECMD rgcmd;
HRESULT hr;
rgcmd.cmdID = cmdID;
rgcmd.cmdf = *pcmdf;
hr = _pmsc->QueryStatus(NULL, 1, &rgcmd, NULL);
*pcmdf = (OLECMDF) rgcmd.cmdf;
return hr;
}
return (E_UNEXPECTED);
}
HRESULT CIEFrameAuto::ExecWB(OLECMDID cmdID, OLECMDEXECOPT cmdexecopt, VARIANT * pvaIn, VARIANT * pvaOut)
{
if (_pmsc)
{
return _pmsc->Exec(NULL, cmdID, cmdexecopt, pvaIn, pvaOut);
}
return (E_UNEXPECTED);
}
STDMETHODIMP CIEFrameAuto::get_Offline(THIS_ VARIANT_BOOL * pbOffline)
{
if (!pbOffline)
return E_INVALIDARG;
*pbOffline = TO_VARIANT_BOOL(m_bOffline);
return S_OK;
}
void SendAmbientPropChange(IOleCommandTarget* pct, int prop)
{
if (pct)
{
VARIANTARG VarArgIn;
VarArgIn.vt = VT_I4;
VarArgIn.lVal = prop;
pct->Exec(&CGID_ShellDocView, SHDVID_AMBIENTPROPCHANGE, 0, &VarArgIn, NULL);
}
}
STDMETHODIMP CIEFrameAuto::put_Offline(THIS_ VARIANT_BOOL bOffline)
{
TraceMsg(TF_SHDAUTO, "Shell automation: CIEFrameAuto:put_Offline called");
if ((m_bOffline && bOffline) || (!(m_bOffline || bOffline))) // The mode is not changing
return S_OK;
m_bOffline = bOffline ? TRUE : FALSE;
// Let children know an ambient property may have changed
//
SendAmbientPropChange(_pmsc, DISPID_AMBIENT_OFFLINEIFNOTCONNECTED);
return S_OK;
}
STDMETHODIMP CIEFrameAuto::get_Silent(THIS_ VARIANT_BOOL * pbSilent)
{
if (!pbSilent)
return E_INVALIDARG;
*pbSilent = TO_VARIANT_BOOL(m_bSilent);
return S_OK;
}
STDMETHODIMP CIEFrameAuto::put_Silent(THIS_ VARIANT_BOOL bSilent)
{
TraceMsg(TF_SHDAUTO, "Shell automation: CIEFrameAuto:put_Silent called");
if ((m_bSilent && bSilent) || (!(m_bSilent || bSilent))) // The mode is not changing
return S_OK;
m_bSilent = bSilent ? TRUE : FALSE;
// Let children know an ambient property may have changed
//
SendAmbientPropChange(_pmsc, DISPID_AMBIENT_SILENT);
return S_OK;
}
//
// NOTE: RegisterAsBrowser is a kind of a misnomer here - zekel 8-SEP-97
// this is used for 3rd party apps to register the browser as being theirs,
// and not being one of our default shell browsers to use and abuse at
// our pleasure. this keeps it out of the reusable winlist. this fixes
// the bug where our welcome.exe page gets reused on a shellexec.
//
HRESULT CIEFrameAuto::get_RegisterAsBrowser(VARIANT_BOOL * pbRegister)
{
if (pbRegister)
{
*pbRegister = _fRegisterAsBrowser ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
return E_INVALIDARG;
}
HRESULT CIEFrameAuto::put_RegisterAsBrowser(VARIANT_BOOL bRegister)
{
if (bRegister)
{
if (_pbs == NULL) //Make sure we have a IBrowserService.
return S_FALSE;
_fRegisterAsBrowser = TRUE;
_pbs->RegisterWindow(TRUE, SWC_3RDPARTY);
return S_OK;
}
//
// we dont support a way to turn it off
return E_FAIL;
}
HRESULT CIEFrameAuto::get_TheaterMode(VARIANT_BOOL * pbRegister)
{
if (!pbRegister)
return E_INVALIDARG;
if (_pbs) {
DWORD dw;
_pbs->GetFlags(&dw);
*pbRegister = TO_VARIANT_BOOL(dw & BSF_THEATERMODE);
return S_OK;
}
// rgardner poor choice of return error code - need better error
// This error puts of "undefined error" dialog
return E_FAIL;
}
HRESULT CIEFrameAuto::put_TheaterMode(VARIANT_BOOL bRegister)
{
if (_pbs) {
_pbs->SetFlags(bRegister ? BSF_THEATERMODE : 0, BSF_THEATERMODE);
return S_OK;
}
return S_FALSE;
}
HRESULT CIEFrameAuto::get_RegisterAsDropTarget(VARIANT_BOOL * pbRegister)
{
if (!pbRegister)
return E_INVALIDARG;
if (_pbs==NULL) {
TraceMsg(DM_WARNING, "CIEA::get_RegisterAsDropTarget called _pbs==NULL");
return E_FAIL;
}
DWORD dw;
_pbs->GetFlags(&dw);
*pbRegister = TO_VARIANT_BOOL(dw & BSF_REGISTERASDROPTARGET);
return S_OK;
}
HRESULT CIEFrameAuto::put_RegisterAsDropTarget(VARIANT_BOOL bRegister)
{
if (_pbs==NULL) {
TraceMsg(DM_WARNING, "CIEA::put_RegisterAsDropTarget called _pbs==NULL");
return E_FAIL;
}
_pbs->SetFlags(bRegister ? BSF_REGISTERASDROPTARGET : 0, BSF_REGISTERASDROPTARGET);
return S_OK;
}
HRESULT CIEFrameAuto::get_AddressBar(VARIANT_BOOL * pValue)
{
BOOL bValue;
HRESULT hres;
if (!pValue)
return E_INVALIDARG;
if (_pbs==NULL) {
TraceMsg(DM_WARNING, "CIEA::get_AddressBar called _pbs==NULL");
return E_FAIL;
}
// Put the processing of this in the main Frame class
bValue = (BOOL)*pValue;
hres = _pbs->IsControlWindowShown(FCW_ADDRESSBAR, &bValue);
*pValue = TO_VARIANT_BOOL(bValue);
return hres;
}
HRESULT CIEFrameAuto::put_AddressBar(VARIANT_BOOL Value)
{
HRESULT hres;
if (_pbs==NULL) {
TraceMsg(DM_WARNING, "CIEA::put_AddressBar called _pbs==NULL");
return E_FAIL;
}
_pbs->SetFlags(BSF_UISETBYAUTOMATION, BSF_UISETBYAUTOMATION);
hres = _pbs->ShowControlWindow(FCW_ADDRESSBAR, (BOOL)Value);
FireEvent_OnAdornment(_GetOuter(), DISPID_ONADDRESSBAR, Value);
return(hres);
}
HRESULT CIEFrameAuto::get_Resizable(VARIANT_BOOL * pValue)
{
HRESULT hres;
DWORD dw;
if (!pValue)
return E_INVALIDARG;
if (_pbs==NULL)
{
TraceMsg(DM_WARNING, "CIEA::get_Resizable called _pbs==NULL");
return E_FAIL;
}
hres = _pbs->GetFlags(&dw);
*pValue = TO_VARIANT_BOOL (dw & BSF_RESIZABLE);
return hres;
}
HRESULT CIEFrameAuto::put_Resizable(VARIANT_BOOL Value)
{
HRESULT hres;
if (_pbs==NULL)
{
TraceMsg(DM_WARNING, "CIEA::put_Resizable called _pbs==NULL");
return E_FAIL;
}
hres = _pbs->SetFlags(
Value ? (BSF_RESIZABLE | BSF_CANMAXIMIZE) : 0,
(BSF_RESIZABLE | BSF_CANMAXIMIZE));
return hres ;
}
void UpdateBrowserReadyState(IUnknown * punk, DWORD dwReadyState)
{
if (punk)
{
IDocNavigate *pdn;
if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IDocNavigate, &pdn))))
{
pdn->OnReadyStateChange(NULL, dwReadyState);
pdn->Release();
}
}
}
HRESULT CIEFrameAuto::put_DefaultReadyState(DWORD dwDefaultReadyState, BOOL fUpdateBrowserReadyState)
{
_dwDefaultReadyState = dwDefaultReadyState;
TraceMsg(TF_SHDNAVIGATE, "CIEA(%x)::psb(%x) new default ReadyState %d", this, _psb, dwDefaultReadyState);
if (fUpdateBrowserReadyState)
{
UpdateBrowserReadyState(_psb, _dwDefaultReadyState);
}
return S_OK;
}
HRESULT CIEFrameAuto::OnDocumentComplete(void)
{
TraceMsg(DM_FRAMEPROPERTY, "CIEFA::OnDocumentComplete called");
DWORD dwCur = GetCurrentTime();
VARIANT varEmpty = { 0 };
if (dwCur - _dwTickPropertySweep > MSEC_PROPSWEEP) {
TraceMsg(DM_FRAMEPROPERTY, "CIEFA::OnDocumentComplete start sweeping");
for (CIEFrameAutoProp *pprop = _pProps; pprop;) {
CIEFrameAutoProp* ppropNext = pprop->Next();
if (pprop->IsExpired(dwCur)) {
TraceMsg(DM_FRAMEPROPERTY, "CIEFA::OnDocumentComplete deleting an expired property");
pprop->SetValue(&varEmpty, this);
}
pprop=ppropNext;
}
_dwTickPropertySweep = dwCur;
}
return S_OK;
}
HRESULT CIEFrameAuto::OnWindowsListMarshalled(void)
{
_fWindowsListMarshalled = TRUE;
return S_OK;
}
HRESULT CIEFrameAuto::SetDocHostFlags(DWORD dwDocHostFlags)
{
_dwDocHostInfoFlags = dwDocHostFlags;
return S_OK;
}
HRESULT CIEFrameAuto::get_ReadyState(READYSTATE * plReadyState)
{
READYSTATE lReadyState = (READYSTATE)_dwDefaultReadyState;
if (_psb)
{
IDocNavigate* pdn;
if (SUCCEEDED(_psb->QueryInterface(IID_PPV_ARG(IDocNavigate, &pdn))))
{
pdn->get_ReadyState((LPDWORD)&lReadyState);
pdn->Release();
}
}
TraceMsg(TF_SHDNAVIGATE, "CIEA(%x)::psb(%x)->get_ReadyState returning %d", this, _psb, lReadyState);
*plReadyState = lReadyState;
return S_OK;
}
STDMETHODIMP CIEFrameAuto::get_TopLevelContainer(VARIANT_BOOL * pBool)
{
*pBool = TRUE;
return NOERROR;
}
STDMETHODIMP CIEFrameAuto::get_Type(BSTR * pbstrType)
{
HRESULT hres = E_FAIL;
*pbstrType = NULL;
IShellView *psv;
if (_psb && SUCCEEDED(hres = _psb->QueryActiveShellView(&psv)) && psv)
{
IOleObject *pobj;
hres = SafeGetItemObject(psv, SVGIO_BACKGROUND, IID_PPV_ARG(IOleObject, &pobj));
if (SUCCEEDED(hres))
{
LPOLESTR pwszUserType;
hres = pobj->GetUserType(USERCLASSTYPE_FULL, &pwszUserType);
if (hres == OLE_S_USEREG)
{
CLSID clsid;
hres = pobj->GetUserClassID(&clsid);
if (SUCCEEDED(hres))
{
hres = OleRegGetUserType(clsid, USERCLASSTYPE_FULL, &pwszUserType);
}
}
if (SUCCEEDED(hres) && pwszUserType)
{
*pbstrType = SysAllocString(pwszUserType);
if (*pbstrType == NULL)
{
hres = E_OUTOFMEMORY;
}
OleFree(pwszUserType);
}
pobj->Release();
}
psv->Release();
}
return hres;
}
HRESULT CIEFrameAuto::SetOwner(IUnknown* punkOwner)
{
ATOMICRELEASE(_pbs);
ATOMICRELEASE(_psp);
ATOMICRELEASE(_psb);
ATOMICRELEASE(_psbProxy);
ATOMICRELEASE(_poctFrameTop);
ATOMICRELEASE(_psbFrameTop);
ATOMICRELEASE(_psbTop);
ATOMICRELEASE(_pmsc);
if (punkOwner)
{
// Check if we're the desktop - if so, we do not act as
// parent frame to our children (desktop components)
_fDesktopFrame = FALSE;
IUnknown *punkDesktop;
if (SUCCEEDED(punkOwner->QueryInterface(SID_SShellDesktop, (void **)&punkDesktop)))
{
_fDesktopFrame = TRUE;
punkDesktop->Release();
}
punkOwner->QueryInterface(IID_PPV_ARG(IBrowserService, &_pbs));
punkOwner->QueryInterface(IID_PPV_ARG(IShellBrowser, &_psb));
UpdateBrowserReadyState(_psb, _dwDefaultReadyState);
HRESULT hresT = punkOwner->QueryInterface(IID_PPV_ARG(IServiceProvider, &_psp));
if (SUCCEEDED(hresT))
{
_psp->QueryService(SID_SShellBrowser, IID_PPV_ARG(IOleCommandTarget, &_pmsc));
_psp->QueryService(SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser, &_psbTop));
_psp->QueryService(SID_STopFrameBrowser, IID_PPV_ARG(IShellBrowser, &_psbFrameTop));
// this is the browser we should tell to navigate if we're asked to navigate
_psp->QueryService(SID_SProxyBrowser, IID_PPV_ARG(IShellBrowser, &_psbProxy));
if (!_psbProxy)
{
_psbProxy = _psb;
_psbProxy->AddRef();
}
// we use _poctFrameTop::Exec to set history selection pidl
if (_psbFrameTop && _psbProxy == _psb)
{
_psbFrameTop->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &_poctFrameTop));
}
// We should always have one of these -- used to notify of frame closing
// and new window navigation.
ASSERT(_psbTop);
ASSERT(_psbFrameTop);
// Since the desktop does not support IOleCommandTarget (intentionally)
// _pmsc could be NULL. No need to RIP here.
//
// ASSERT(_pmsc);
}
ASSERT(_pbs);
ASSERT(_psp);
ASSERT(_psb);
}
else
{
_omwin.DeInit();
//
// We need to clear the property list here (than in the destructor)
// to break the circular ref-count.
//
_ClearPropertyList();
}
return S_OK;
}
HRESULT CIEFrameAuto::SetOwnerHwnd(HWND hwndOwner)
{
_hwnd = hwndOwner;
return S_OK;
}
HWND CIEFrameAuto::_GetHWND()
{
if (!_hwnd && _pbs)
{
IOleWindow * pow;
if (SUCCEEDED(_pbs->QueryInterface(IID_PPV_ARG(IOleWindow, &pow))))
{
pow->GetWindow(&_hwnd);
pow->Release();
}
}
// people that call this assume that we always succeed
//
// ... people who call this better quit making incorrect
// assumptions. If we can't guarantee an hwnd the caller
// can't assume they'll be getting one. (edwardp)
if (_hwnd == NULL)
{
TraceMsg(DM_WARNING, "CIEA::_GetHWND returning NULL");
}
return _hwnd;
}
// *** IConnectionPointContainer ***
CConnectionPoint* CIEFrameAuto::_FindCConnectionPointNoRef(BOOL fdisp, REFIID iid)
{
CConnectionPoint* pccp;
// VB team claims its safe to fire new dispids to old event sinks.
// This will cause a fault on an old event sink if they assumed
// only the dispids in the old typelib would ever be fired and they
// did no bounds checking and jumped into space. Let's trust the VB
// team and see if we discover any poor event sinks.
//
// They also say we sould just extend our primary dispinterface instead
// of replace it with an equivalent but different one. That approach
// unfortunately leaves the offending bad event mechanism sit in
// the VB programmer's face.
//
// I want to do three things:
// 1. Change the primary dispinterface to see what headaches that causes.
// This has nice positives and its easy to change back later. (fdisp==TRUE case)
// 2. Don't fire old events to consumers of the new dispinterface.
// This will flush out any compatability issues of containers
// connecting to the default dispinterface when they really
// wanted the old DIID.
// 3. Do fire new events to old sinks. This will flush out any
// compatability issues with VBs theory.
//
// We can't do all three, so let's choose 1 and 2. We can
// force 3 by randomly firing out-of-range dispids if this
// is important...
//
if (IsEqualIID(iid, DIID_DWebBrowserEvents2) ||
(fdisp && IsEqualIID(iid, IID_IDispatch)))
{
pccp = &m_cpWebBrowserEvents2;
}
else if (IsEqualIID(iid, DIID_DWebBrowserEvents))
{
pccp = &m_cpWebBrowserEvents;
}
else if (IsEqualIID(iid, IID_IPropertyNotifySink))
{
pccp = &m_cpPropNotify;
}
else
{
pccp = NULL;
}
return pccp;
}
STDMETHODIMP CIEFrameAuto::EnumConnectionPoints(LPENUMCONNECTIONPOINTS * ppEnum)
{
return CreateInstance_IEnumConnectionPoints(ppEnum, 3,
m_cpWebBrowserEvents2.CastToIConnectionPoint(),
m_cpWebBrowserEvents.CastToIConnectionPoint(),
m_cpPropNotify.CastToIConnectionPoint());
}
//=============================================================================
// Our class factory
class CIEFrameClassFactory : public IClassFactory
{
public:
CIEFrameClassFactory(IUnknown* punkAuto, REFCLSID clsid, UINT uFlags);
// IUnKnown
STDMETHODIMP QueryInterface(REFIID, void **);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IClassFactory
STDMETHODIMP CreateInstance(
IUnknown *pUnkOuter, REFIID riid, void **ppvObject);
STDMETHODIMP LockServer(BOOL fLock);
// Helper functions...
HRESULT CleanUpAutomationObject();
void Revoke(void);
protected:
~CIEFrameClassFactory();
LONG _cRef;
IUnknown *_punkAuto; // Only for the first one for the process
DWORD _dwRegister; // The value returned from CoRegisterClassObject;
UINT _uFlags; // extra COF_ bits to pass to our create browser window code
};
#define AssertParking() ASSERT(g_tidParking==0 || g_tidParking == GetCurrentThreadId())
#ifdef NO_MARSHALLING
EXTERN_C void IEFrameNewWindowSameThread(IETHREADPARAM* piei);
#endif
CIEFrameClassFactory::CIEFrameClassFactory(IUnknown* punkAuto, REFCLSID clsid, UINT uFlags)
: _cRef(1), _dwRegister((DWORD)-1), _uFlags(uFlags)
{
AssertParking();
if (punkAuto)
{
_punkAuto = punkAuto;
punkAuto->AddRef();
}
HRESULT hres = CoRegisterClassObject(clsid, this, CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER,
REGCLS_MULTIPLEUSE, &_dwRegister);
if (FAILED(hres))
{
_dwRegister = (DWORD)-1;
}
TraceMsg(TF_SHDLIFE, "ctor CIEFrameClassFactory %x", this);
}
CIEFrameClassFactory::~CIEFrameClassFactory()
{
AssertParking();
ASSERT(_dwRegister == (DWORD)-1);
if (_punkAuto)
_punkAuto->Release();
TraceMsg(TF_SHDLIFE, "dtor CIEFrameClassFactory %x", this);
}
void CIEFrameClassFactory::Revoke(void)
{
if (_dwRegister != (DWORD)-1)
{
CoRevokeClassObject(_dwRegister);
_dwRegister = (DWORD)-1;
}
}
HRESULT CIEFrameClassFactory::QueryInterface(REFIID riid, void **ppvObj)
{
static const QITAB qit[] = {
QITABENT(CIEFrameClassFactory, IClassFactory), // IID_IClassFactory
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}
ULONG CIEFrameClassFactory::AddRef(void)
{
return InterlockedIncrement(&_cRef);
}
ULONG CIEFrameClassFactory::Release(void)
{
ASSERT( 0 != _cRef );
ULONG cRef = InterlockedDecrement(&_cRef);
if ( 0 == cRef )
{
delete this;
}
return cRef;
}
//
// We call this function to clean up the automation object if something
// goes wrong and OLE did not pick it up. Under a normal circumstance,
// _punkAuto is supposed to be NULL.
//
HRESULT CIEFrameClassFactory::CleanUpAutomationObject()
{
AssertParking();
ASSERT(_punkAuto==NULL);
ATOMICRELEASE(_punkAuto);
return S_OK;
}
class IETHREADHANDSHAKE : public IEFreeThreadedHandShake
{
public:
// *** IUnknown methods ***
STDMETHODIMP QueryInterface(THIS_ REFIID riid, void ** ppvObj) { *ppvObj = NULL; return E_NOTIMPL; } // HACK: we're not a real com object
STDMETHODIMP_(ULONG) AddRef(THIS);
STDMETHODIMP_(ULONG) Release(THIS);
// *** IIEFreeThreadedHandShake methods ***
STDMETHODIMP_(void) PutHevent(THIS_ HANDLE hevent) { _hevent = hevent; }
STDMETHODIMP_(HANDLE) GetHevent(THIS) { return _hevent; }
STDMETHODIMP_(void) PutHresult(THIS_ HRESULT hres) { _hres = hres; }
STDMETHODIMP_(HRESULT) GetHresult(THIS) { return _hres; }
STDMETHODIMP_(IStream*) GetStream(THIS) { return _pstm; }
protected:
LONG _cRef; // ref-count (must be thread safe)
HANDLE _hevent;
IStream* _pstm;
HRESULT _hres; // result from CoMarshalInterface
friend IEFreeThreadedHandShake* CreateIETHREADHANDSHAKE();
IETHREADHANDSHAKE(HANDLE heventIn, IStream* pstmIn);
~IETHREADHANDSHAKE();
};
IETHREADHANDSHAKE::IETHREADHANDSHAKE(HANDLE heventIn, IStream* pstmIn)
: _cRef(1), _hevent(heventIn), _pstm(pstmIn), _hres(E_FAIL)
{
TraceMsg(TF_SHDLIFE, "ctor IETHREADHANDSHAKE %x", this);
ASSERT(_hevent);
ASSERT(_pstm);
_pstm->AddRef();
}
IETHREADHANDSHAKE::~IETHREADHANDSHAKE()
{
TraceMsg(TF_SHDLIFE, "dtor IETHREADHANDSHAKE %x", this);
CloseHandle(_hevent);
_pstm->Release();
}
ULONG IETHREADHANDSHAKE::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG IETHREADHANDSHAKE::Release()
{
ASSERT( 0 != _cRef );
ULONG cRef = InterlockedDecrement(&_cRef);
if ( 0 == cRef )
{
delete this;
}
return cRef;
}
IEFreeThreadedHandShake* CreateIETHREADHANDSHAKE()
{
IEFreeThreadedHandShake* piehs = NULL;
HANDLE hevent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (hevent)
{
IStream* pstm;
HRESULT hres = CreateStreamOnHGlobal(NULL, TRUE, &pstm);
if (SUCCEEDED(hres))
{
IETHREADHANDSHAKE* p = new IETHREADHANDSHAKE(hevent, pstm);
if (p)
{
// this is free threaded, so we can't know which thread will free it.
// technically our caller should do this, but we return an
// interface and not the class itself...
piehs = SAFECAST(p, IEFreeThreadedHandShake*);
}
pstm->Release();
}
if (!piehs)
CloseHandle(hevent);
}
return piehs;
}
HRESULT CIEFrameClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject)
{
HRESULT hres = E_FAIL;
//
// Check if this is the very first automation request.
//
if (_punkAuto && g_tidParking == GetCurrentThreadId())
{
//
// Yes, return the first browser object.
//
hres = _punkAuto->QueryInterface(riid, ppvObject);
// We don't want to return it twice.
ATOMICRELEASE(_punkAuto);
}
else
{
#ifndef NO_MARSHALLING
//
// No, create a new browser window in a new thread and
// return a marshalled pointer.
//
hres = E_OUTOFMEMORY;
IEFreeThreadedHandShake* piehs = CreateIETHREADHANDSHAKE();
if (piehs)
{
IETHREADPARAM *piei = SHCreateIETHREADPARAM(NULL, SW_SHOWNORMAL, NULL, piehs);
if (piei)
{
piei->uFlags |= (_uFlags | COF_CREATENEWWINDOW | COF_NOFINDWINDOW | COF_INPROC);
DWORD idThread;
HANDLE hthread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SHOpenFolderWindow, piei, 0, &idThread);
if (hthread)
{
// Wait until either
// (1) the thread is terminated
// (2) the event is signaled (by the new thread)
// (3) time-out
//
// Note that we call MsgWaitForMultipleObjects
// to avoid dead lock in case the other thread
// sends a broadcast message to us (unlikely, but
// theoreticallly possible).
//
HANDLE ah[] = { piehs->GetHevent(), hthread };
DWORD dwStart = GetTickCount();
#define MSEC_MAXWAIT (30 * 1000)
DWORD dwWait = MSEC_MAXWAIT;
DWORD dwWaitResult;
do {
dwWaitResult = MsgWaitForMultipleObjects(ARRAYSIZE(ah), ah, FALSE,
dwWait, QS_SENDMESSAGE);
if (dwWaitResult == WAIT_OBJECT_0 + ARRAYSIZE(ah)) // msg input
{
// allow pending SendMessage() to go through
MSG msg;
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
}
else
break; // signaled or timed out, exit the loop
// Update the dwWait. It will become larger
// than MSEC_MAXWAIT if we wait more than that.
dwWait = dwStart + MSEC_MAXWAIT - GetTickCount();
} while (dwWait <= MSEC_MAXWAIT);
switch (dwWaitResult)
{
default:
ASSERT(0);
case WAIT_OBJECT_0 + 1:
TraceMsg(DM_ERROR, "CIECF::CI thread terminated before signaling us"); // probably leak the IETHREADPARAM and IETHREADHANDSHAKE in this case
hres = E_FAIL;
break;
case WAIT_OBJECT_0 + ARRAYSIZE(ah): // msg input
case WAIT_TIMEOUT:
TraceMsg(DM_ERROR, "CIECF::CI time out");
hres = E_FAIL;
break;
case WAIT_OBJECT_0: // hevent signaled
hres = piehs->GetHresult();
if (SUCCEEDED(hres))
{
IStream* pstm = piehs->GetStream();
pstm->Seek(c_li0, STREAM_SEEK_SET, NULL);
hres = CoUnmarshalInterface(pstm, riid, ppvObject);
}
else
TraceMsg(DM_ERROR, "CIECF::CI piehs->hres has an error %x", hres);
break;
}
CloseHandle(hthread);
}
else
{
SHDestroyIETHREADPARAM(piei);
hres = E_OUTOFMEMORY;
}
}
else
{
hres = E_OUTOFMEMORY;
TraceMsg(DM_ERROR, "CIECF::CI new IETHREADPARAM failed");
}
piehs->Release();
}
#else // !NO_MARSHALLING
//
// Create a new window on the same thread
//
IEFreeThreadedHandShake* piehs = CreateIETHREADHANDSHAKE();
if (piehs)
{
IETHREADPARAM* piei = SHCreateIETHREADPARAM(NULL, SW_SHOWNORMAL, NULL, piehs);
if (piei)
IEFrameNewWindowSameThread(piei);
if (SUCCEEDED(piehs->GetHresult()))
{
IUnknown* punk;
IStream * pstm = piehs->GetStream();
if (pstm)
{
ULONG pcbRead = 0;
pstm->Seek(c_li0, STREAM_SEEK_SET, NULL);
hres = pstm->Read(&punk, sizeof(punk), &pcbRead);
if (SUCCEEDED(hres))
{
hres = punk->QueryInterface(riid, ppvObject);
punk->Release();
}
}
}
else
{
hres = piehs->GetHresult();
TraceMsg(DM_ERROR, "CIECF::CI piehs->hres has an error %x", piehs->GetHresult());
}
piehs->Release();
}
#endif // NO_MARSHALLING
}
return hres;
}
HRESULT CIEFrameClassFactory::LockServer(BOOL fLock)
{
return S_OK;
}
BOOL Is98orEarlier()
{
BOOL bRet = FALSE;
OSVERSIONINFOA s_osvi;
s_osvi.dwOSVersionInfoSize = sizeof(s_osvi);
GetVersionExA(&s_osvi);
bRet = s_osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
s_osvi.dwMajorVersion == 4;
return bRet;
}
void GetEventURL(LPCITEMIDLIST pidl, LBSTR::CString & p_rstrPath)
{
HRESULT hres = E_FAIL;
if (pidl)
{
LPTSTR pstrPath = p_rstrPath.GetBuffer(MAX_URL_STRING);
if (p_rstrPath.GetAllocLength() < MAX_URL_STRING)
{
TraceMsg(TF_WARNING, "GetEventURL() - p_rstrPath Allocation Failed!");
hres = E_OUTOFMEMORY;
}
else
{
hres = IEGetDisplayName(pidl, pstrPath, SHGDN_FORPARSING);
// Let CString class own the buffer again.
p_rstrPath.ReleaseBuffer();
}
if (FAILED(hres) && Is98orEarlier())
{
LBSTR::CString strTempUrl;
LPTSTR pstrTempUrl = strTempUrl.GetBuffer(INTERNET_MAX_URL_LENGTH);
if (strTempUrl.GetAllocLength() < INTERNET_MAX_URL_LENGTH)
{
TraceMsg(TF_WARNING, "GetEventURL() - strTempUrl Allocation Failed!");
hres = E_OUTOFMEMORY;
}
else
{
hres = IEGetDisplayName(pidl, pstrTempUrl, SHGDN_NORMAL);
// Let CString class own the buffer again.
strTempUrl.ReleaseBuffer();
}
if (SUCCEEDED(hres))
{
LPTSTR pFoundStr = NULL;
BOOL bNotMachineName = FALSE;
pFoundStr = StrChr(strTempUrl, _T(':'));
if (pFoundStr)
{
bNotMachineName = TRUE;
}
else if ((strTempUrl[0] == _T('\\')) ||
(strTempUrl[0] == _T('/')))
{
bNotMachineName = TRUE;
}
if (bNotMachineName)
{
p_rstrPath = strTempUrl;
}
else
{
p_rstrPath = _T("\\\\") + strTempUrl;
}
}
}
}
if (FAILED(hres))
{
p_rstrPath.Empty();
}
}
HRESULT GetWBConnectionPoints(IUnknown* punk, IConnectionPoint **ppccp1, IConnectionPoint **ppccp2);
HRESULT GetTopWBConnectionPoints(IUnknown* punk, IConnectionPoint **ppccpTop1, IConnectionPoint **ppccpTop2)
{
HRESULT hres = E_FAIL;
if (ppccpTop1)
*ppccpTop1 = NULL;
if (ppccpTop2)
*ppccpTop2 = NULL;
IServiceProvider *pspSB;
if (punk && SUCCEEDED(IUnknown_QueryService(punk, SID_STopFrameBrowser, IID_PPV_ARG(IServiceProvider, &pspSB))))
{
IWebBrowser2 *pwb;
if (SUCCEEDED(pspSB->QueryService(SID_SInternetExplorer, IID_PPV_ARG(IWebBrowser2, &pwb))))
{
// We only want the toplevel interfaces if we're a frameset
//
if (!IsSameObject(punk, pwb))
{
hres = GetWBConnectionPoints(pwb, ppccpTop1, ppccpTop2);
}
pwb->Release();
}
pspSB->Release();
}
return hres;
}
// Fires a NavigateComplete (DISPID_NAVIGATECOMPLETE)
// event to container if there are any advise sinks
void FireEvent_NavigateComplete(IUnknown* punk, IWebBrowser2* pwb2, LPCITEMIDLIST pidl, HWND hwnd)
{
IConnectionPoint* pcp1 = NULL;
IConnectionPoint* pcpTopWBEvt2 = NULL;
IConnectionPoint* pcpWBEvt2 = NULL;
// if we don't have any sinks, then there's nothing to do. we intentionally
// ignore errors here.
//
LBSTR::CString strPath;
GetEventURL(pidl, strPath);
//
// Notify IEDDE of navigate complete.
//
IEDDE_AfterNavigate(strPath, hwnd);
// Fire NavigateComplete2 off the parent and top-level frames.
// We only fire [Frame]NavigateComplete off the top-level
// frame for backward compatibility.
//
GetTopWBConnectionPoints(punk, &pcp1, &pcpTopWBEvt2);
DISPID dispid = pcp1 ? DISPID_FRAMENAVIGATECOMPLETE : DISPID_NAVIGATECOMPLETE;
GetWBConnectionPoints(punk, pcp1 ? NULL : &pcp1, &pcpWBEvt2);
if (pcpTopWBEvt2 || pcpWBEvt2)
{
VARIANT vURL = {0};
BOOL bSysAllocated = FALSE;
// If IEGetDisplayName above failed, pack the PIDL in the variant
//
// Try to keep OLEAUT32 unloaded if possible.
//
V_VT(&vURL) = VT_BSTR;
// If OLEAUT32 is already loaded
if (GetModuleHandle(TEXT("OLEAUT32.DLL")))
{
// then do the SysAllocString
V_BSTR(&vURL) = SysAllocString(strPath);
// What happens if this comes back NULL?
bSysAllocated = TRUE;
}
else
{
// else use the stack version
V_BSTR(&vURL) = strPath;
}
TraceMsg(TF_SHDCONTROL, "Event: NavigateComplete2[%ls]", strPath);
// Fire the event to the parent first and then the top-level object.
// For symmetry we fire NavigateComplete2 packed as a Variant.
//
if (pcpWBEvt2)
{
DoInvokeParamHelper(punk, pcpWBEvt2, NULL, NULL, DISPID_NAVIGATECOMPLETE2, 2,
VT_DISPATCH, pwb2,
VT_VARIANT|VT_BYREF, &vURL);
ATOMICRELEASE(pcpWBEvt2);
}
if (pcpTopWBEvt2)
{
DoInvokeParamHelper(punk, pcpTopWBEvt2, NULL, NULL, DISPID_NAVIGATECOMPLETE2, 2,
VT_DISPATCH, pwb2,
VT_VARIANT|VT_BYREF, &vURL);
ATOMICRELEASE(pcpTopWBEvt2);
}
// Since we pass the BSTR in a VT_VARIANT|VT_BYREF, OLEAUT32 might have freed and reallocated it.
//
ASSERT(V_VT(&vURL) == VT_BSTR);
if (bSysAllocated)
{
SysFreeString(V_BSTR(&vURL));
}
}
if (pcp1)
{
//
// Compuserve History manager compatability: Don't fire NavigateComplete if it's a javascript:
// or vbscript: URL.
//
if (GetUrlSchemeW(strPath) != URL_SCHEME_JAVASCRIPT &&
GetUrlSchemeW(strPath) != URL_SCHEME_VBSCRIPT)
{
// IE3 did not fire on NULL pidl
if (pidl)
{
TraceMsg(TF_SHDCONTROL, "Event: NavigateComplete[%ls]", strPath);
// call DoInvokeParam to package up parameters and call
// IDispatch::Invoke on the container.
//
// This pseudo-BSTR is passed as a straight BSTR so doesn't need to be SysAllocString'ed.
//
DoInvokeParamHelper(punk, pcp1, NULL, NULL, dispid, 1, VT_BSTR, strPath);
}
}
ATOMICRELEASE(pcp1);
}
}
void FireEvent_DocumentComplete(IUnknown* punk, IWebBrowser2* pwb2, LPCITEMIDLIST pidl)
{
IConnectionPoint* pcpTopWBEvt2 = NULL;
IConnectionPoint* pcpWBEvt2 = NULL;
// TODO: (mwatt) Investigate why we are occasionally getting bogus DocumentComplete events
// with null disp pointers.
if (!punk)
{
return;
}
LBSTR::CString strPath;
GetEventURL(pidl, strPath);
// Fire DocumentComplete off the parent and top-level frames.
//
GetTopWBConnectionPoints(punk, NULL, &pcpTopWBEvt2);
GetWBConnectionPoints(punk, NULL, &pcpWBEvt2);
if (pcpTopWBEvt2 || pcpWBEvt2)
{
VARIANT vURL = {0};
BOOL bSysAllocated = FALSE;
// If IEGetDisplayName above failed, pack the PIDL in the variant
//
// Try to keep OLEAUT32 unloaded if possible.
//
V_VT(&vURL) = VT_BSTR;
// If OLEAUT32 is already loaded
if (GetModuleHandle(TEXT("OLEAUT32.DLL")))
{
// then do the SysAllocString
V_BSTR(&vURL) = SysAllocString(strPath);
bSysAllocated = TRUE;
}
else
{
// else use the stack version
V_BSTR(&vURL) = strPath;
}
// Fire the event to the parent first and then the top-level object.
//
if (pcpWBEvt2)
{
DoInvokeParamHelper(punk, pcpWBEvt2, NULL, NULL, DISPID_DOCUMENTCOMPLETE, 2,
VT_DISPATCH, pwb2,
VT_VARIANT|VT_BYREF, &vURL);
ATOMICRELEASE(pcpWBEvt2);
}
if (pcpTopWBEvt2)
{
DoInvokeParamHelper(punk, pcpTopWBEvt2, NULL, NULL, DISPID_DOCUMENTCOMPLETE, 2,
VT_DISPATCH, pwb2,
VT_VARIANT|VT_BYREF, &vURL);
ATOMICRELEASE(pcpTopWBEvt2);
}
// Since we pass the BSTR in a VT_VARIANT|VT_BYREF, OLEAUT32 might have freed and reallocated it.
//
ASSERT(V_VT(&vURL) == VT_BSTR);
if (bSysAllocated)
{
SysFreeString(V_BSTR(&vURL));
}
}
IEFrameAuto* pief;
if (SUCCEEDED(pwb2->QueryInterface(IID_PPV_ARG(IEFrameAuto, &pief))))
{
pief->OnDocumentComplete();
pief->Release();
}
}
void AllocEventStuff(LPCTSTR pszFrameName, BSTR * pbstrFrameName,
LPCTSTR pszHeaders, BSTR * pbstrHeaders,
LPBYTE pPostData, DWORD cbPostData, VARIANTARG * pvaPostData)
{
SAFEARRAY * psaPostData = NULL;
// allocate BSTRs for frame name, headers
*pbstrFrameName = NULL;
if (pszFrameName && pszFrameName[0])
{
*pbstrFrameName = SysAllocStringT(pszFrameName);
}
*pbstrHeaders = NULL;
if (pszHeaders && pszHeaders[0])
{
*pbstrHeaders = SysAllocStringT(pszHeaders);
}
if (pPostData && cbPostData) {
// make a SAFEARRAY for post data
psaPostData = MakeSafeArrayFromData(pPostData,cbPostData);
}
// put the post data SAFEARRAY into a variant so we can pass through automation
VariantInit(pvaPostData);
if (psaPostData) {
pvaPostData->vt = VT_ARRAY | VT_UI1;
pvaPostData->parray = psaPostData;
}
}
void FreeEventStuff(BSTR bstrFrameName, BSTR bstrHeaders, VARIANTARG * pvaPostData)
{
// free the things we allocated
if (bstrFrameName)
SysFreeString(bstrFrameName);
if (bstrHeaders)
SysFreeString(bstrHeaders);
if (pvaPostData->parray)
{
ASSERT(pvaPostData->vt == (VT_ARRAY | VT_UI1));
VariantClearLazy(pvaPostData);
}
}
/*******************************************************************
NAME: FireEvent_BeforeNavigate
SYNOPSIS: Fires a BeforeNavigate (DISPID_BEFORENAVIGATE) event to container
if there are any advise sinks
NOTES: If the container wants to cancel this navigation,
it fills in pfCancel with TRUE and we should cancel.
********************************************************************/
void FireEvent_BeforeNavigate(IUnknown* punk, HWND hwnd, IWebBrowser2* pwb2,
LPCITEMIDLIST pidl,LPCWSTR pwzLocation,
DWORD dwFlags,LPCTSTR pszFrameName,LPBYTE pPostData,
DWORD cbPostData,LPCTSTR pszHeaders,BOOL * pfProcessedInOut)
{
HRESULT hres = E_FAIL;
IConnectionPoint* pcpTopWBEvt1 = NULL;
IConnectionPoint* pcpTopWBEvt2 = NULL;
IConnectionPoint* pcpWBEvt2 = NULL;
BSTR bstrFrameName = NULL;
BSTR bstrHeaders = NULL;
VARIANTARG vaPostData;
ASSERT(pfProcessedInOut);
//
// HACKHACK (5.5 bug#98986) for fault caused by FrontPage indexing
// past the end of this bool (instead of V_BOOLREF, they
// use V_VARIANTREF->boolVal (CIEControl::XEventSink::Invoke))
// and trashing our stack.
// This has been entered as a bug for Office10, the contact
// is TCrowley our PM is KamV. (marcmill 1/04/2000)
//
union tagFrontPageHack {
BOOL fCancel;
VARIANT varBogus;
} CancelHack = { 0 };
BOOL *pfProcessed = &CancelHack.fCancel;
// We start with "unprocessed"
//
ASSERT(*pfProcessed == FALSE);
// Build the URL name
//
LBSTR::CString strPath;
GetEventURL(pidl, strPath);
// Fire BeforeNavigate2 off the parent and top-level frames.
// We only fire [Frame]BeforeNavigate off the top-level
// frame for backward compatibility.
//
GetTopWBConnectionPoints(punk, &pcpTopWBEvt1, &pcpTopWBEvt2);
DISPID dispid = pcpTopWBEvt1 ? DISPID_FRAMEBEFORENAVIGATE : DISPID_BEFORENAVIGATE;
GetWBConnectionPoints(punk, pcpTopWBEvt1 ? NULL : &pcpTopWBEvt1, &pcpWBEvt2);
// Our caller couldn't pass in the proper IExpDispSupport since
// it may have been aggregated. We do the QI here. Only call
// AllocEventStuff if we really are going to fire an event.
//
if (pcpTopWBEvt1 || pcpTopWBEvt2 || pcpWBEvt2)
{
AllocEventStuff(pszFrameName, &bstrFrameName, pszHeaders, &bstrHeaders, pPostData, cbPostData, &vaPostData);
}
// We fire BeforeNavigate2 before DDE because whoever created us may
// redirect this navigate by cancelling and trying again. DDE will get
// notified on the redirected Navigate. IE3 didn't do it this way,
// so fire the BeforeNavigate event last...
//
if (pcpTopWBEvt2 || pcpWBEvt2)
{
// For symmetry we pack everything in variants
//
// If FAILED(hresGDN) then pack URL as PIDL, not BSTR
//
BOOL bSysAllocated = FALSE;
VARIANT vURL = {0};
V_VT(&vURL) = VT_BSTR;
if (GetModuleHandle(TEXT("OLEAUT32.DLL")))
{
// then do the SysAllocString
V_BSTR(&vURL) = SysAllocString(strPath);
bSysAllocated = TRUE;
}
else
{
// else use the stack version
V_BSTR(&vURL) = strPath;
}
VARIANT vFlags = {0};
V_VT(&vFlags) = VT_I4;
V_I4(&vFlags) = dwFlags;
VARIANT vFrameName = {0};
V_VT(&vFrameName) = VT_BSTR;
V_BSTR(&vFrameName) = bstrFrameName;
VARIANT vPostData = {0};
V_VT(&vPostData) = VT_VARIANT | VT_BYREF;
V_VARIANTREF(&vPostData) = &vaPostData;
VARIANT vHeaders = {0};
V_VT(&vHeaders) = VT_BSTR;
V_BSTR(&vHeaders) = bstrHeaders;
TraceMsg(TF_SHDCONTROL, "Event: BeforeNavigate2[%ls]", strPath);
// Fire the event ot the parent first and then the top-level object.
//
if (pcpWBEvt2)
{
DoInvokeParamHelper(punk, pcpWBEvt2, pfProcessed, NULL, DISPID_BEFORENAVIGATE2, 7,
VT_DISPATCH, pwb2,
VT_VARIANT | VT_BYREF, &vURL,
VT_VARIANT | VT_BYREF, &vFlags,
VT_VARIANT | VT_BYREF, &vFrameName,
VT_VARIANT | VT_BYREF, &vPostData,
VT_VARIANT | VT_BYREF, &vHeaders,
VT_BOOL | VT_BYREF, pfProcessed);
}
// Only continue if the parent object didn't cancel.
//
if (pcpTopWBEvt2 && !*pfProcessed)
{
DoInvokeParamHelper(punk, pcpTopWBEvt2, pfProcessed, NULL, DISPID_BEFORENAVIGATE2, 7,
VT_DISPATCH, pwb2,
VT_VARIANT | VT_BYREF, &vURL,
VT_VARIANT | VT_BYREF, &vFlags,
VT_VARIANT | VT_BYREF, &vFrameName,
VT_VARIANT | VT_BYREF, &vPostData,
VT_VARIANT | VT_BYREF, &vHeaders,
VT_BOOL | VT_BYREF, pfProcessed);
}
if (bSysAllocated)
{
SysFreeString(V_BSTR(&vURL));
}
bstrFrameName = V_BSTR(&vFrameName);
bstrHeaders = V_BSTR(&vHeaders);
}
if (*pfProcessed)
goto Exit;
//
// NOTE: IE3 called the IEDDE hook before BeforeNavigate.
//
IEDDE_BeforeNavigate(strPath, pfProcessed);
if (*pfProcessed)
goto Exit;
//
// Compuserve History manager compatability: Don't fire BeforeNavigate if it's a javascript:
// or vbscript: URL.
//
if (pcpTopWBEvt1
&& GetUrlSchemeW(strPath) != URL_SCHEME_JAVASCRIPT
&& GetUrlSchemeW(strPath) != URL_SCHEME_VBSCRIPT)
{
TraceMsg(TF_SHDCONTROL, "Event: BeforeNavigate[%ls]", strPath);
// call DoInvokeParam to package up these parameters and call
// IDispatch::Invoke on the container.
DoInvokeParamHelper(punk, pcpTopWBEvt1, pfProcessed,NULL, dispid, 6,
VT_BSTR, strPath, // URL
VT_I4, dwFlags, // flags
VT_BSTR, bstrFrameName, // target frame name
VT_VARIANT | VT_BYREF, &vaPostData, // post data
VT_BSTR, bstrHeaders, // headers
VT_BOOL | VT_BYREF, pfProcessed); // BOOL * for indicating "processed"
}
Exit:
*pfProcessedInOut = *pfProcessed; // HACK for FrontPage -- see above for details
if (pcpTopWBEvt1 || pcpTopWBEvt2 || pcpWBEvt2)
{
FreeEventStuff(bstrFrameName, bstrHeaders, &vaPostData);
ATOMICRELEASE(pcpTopWBEvt1);
ATOMICRELEASE(pcpTopWBEvt2);
ATOMICRELEASE(pcpWBEvt2);
}
}
/*******************************************************************
NAME: FireEvent_NavigateError
SYNOPSIS: Fires a NavigateError (DISPID_NAVIGATEERROR) event
to the container if there are any advise sinks
NOTES: If the container wants to cancel
autosearch and friendly error pages,
it fills in pfCancel with TRUE and we should cancel.
********************************************************************/
void FireEvent_NavigateError(IUnknown * punk,
IWebBrowser2 * pwb2,
LPCITEMIDLIST pidl,
BSTR bstrTargetFrameName,
DWORD dwStatusCode,
BOOL * pfCancel)
{
// If we find that the dwStatusCode can legally be 0,
// we should just return from this method and not
// fire the event. dwStatusCode == 0 implies no error.
//
ASSERT(dwStatusCode != 0);
BSTR bstrFrameName = NULL;
if (bstrTargetFrameName && bstrTargetFrameName[0])
{
bstrFrameName = SysAllocStringT(bstrTargetFrameName);
}
// if we don't have any sinks, then there's nothing to do. we intentionally
// ignore errors here.
IConnectionPoint * pcpTopWBEvt2 = NULL;
IConnectionPoint * pcpWBEvt2 = NULL;
*pfCancel = FALSE;
// Fire event off the parent and top-level frames.
//
GetTopWBConnectionPoints(punk, NULL, &pcpTopWBEvt2);
GetWBConnectionPoints(punk, NULL, &pcpWBEvt2);
// Need to convert the URL to version that matches BN2
LBSTR::CString strPath;
BOOL bSysAllocated = FALSE;
GetEventURL(pidl, strPath);
VARIANT vTargetURL = {0};
V_VT(&vTargetURL) = VT_BSTR;
if (GetModuleHandle(TEXT("OLEAUT32.DLL")))
{
// then do the SysAllocString
V_BSTR(&vTargetURL) = SysAllocString(strPath);
bSysAllocated = TRUE;
}
else
{
// else use the stack version
V_BSTR(&vTargetURL) = strPath;
}
VARIANT vStatusCode = {0};
V_VT(&vStatusCode) = VT_I4;
V_I4(&vStatusCode) = dwStatusCode;
VARIANT vTargetFrame = {0};
V_VT(&vTargetFrame) = VT_BSTR;
V_BSTR(&vTargetFrame) = bstrFrameName;
// Fire the event to the parent first and then the top-level object.
//
if (pcpWBEvt2)
{
DoInvokeParamHelper(punk, pcpWBEvt2, NULL, NULL, DISPID_NAVIGATEERROR, 5,
VT_DISPATCH, pwb2,
VT_VARIANT | VT_BYREF, &vTargetURL,
VT_VARIANT | VT_BYREF, &vTargetFrame,
VT_VARIANT | VT_BYREF, &vStatusCode,
VT_BOOL | VT_BYREF, pfCancel);
ATOMICRELEASE(pcpWBEvt2);
}
if (pcpTopWBEvt2)
{
DoInvokeParamHelper(punk, pcpTopWBEvt2, NULL, NULL, DISPID_NAVIGATEERROR, 5,
VT_DISPATCH, pwb2,
VT_VARIANT | VT_BYREF, &vTargetURL,
VT_VARIANT | VT_BYREF, &vTargetFrame,
VT_VARIANT | VT_BYREF, &vStatusCode,
VT_BOOL | VT_BYREF, pfCancel);
ATOMICRELEASE(pcpTopWBEvt2);
}
if (bSysAllocated)
{
SysFreeString(V_BSTR(&vTargetURL));
}
bstrFrameName = V_BSTR(&vTargetFrame);
if (bstrFrameName)
{
SysFreeString(bstrFrameName);
}
}
/*******************************************************************
NAME: FireEvent_PrintTemplateEvent
SYNOPSIS: Fires a PrintTemplateInstantiation (DISPID_PRINTTEMPLATEINSTANTIATION) or
a PrintTemplateTeardown (DISPID_PRINTTEMPLATETEARDOWN) event to container
if there are any advise sinks
********************************************************************/
void FireEvent_PrintTemplateEvent(IUnknown* punk, IWebBrowser2* pwb2, DISPID dispidPrintEvent)
{
// if we don't have any sinks, then there's nothing to do. we intentionally
// ignore errors here.
IConnectionPoint* pcpTopWBEvt2 = NULL;
IConnectionPoint* pcpWBEvt2 = NULL;
// Fire the event off the parent and top-level frames.
//
GetTopWBConnectionPoints(punk, NULL, &pcpTopWBEvt2);
GetWBConnectionPoints(punk, NULL, &pcpWBEvt2);
// Fire the event to the parent first and then the top-level object.
//
if (pcpWBEvt2)
{
DoInvokeParamHelper(punk, pcpWBEvt2, NULL, NULL, dispidPrintEvent, 1,
VT_DISPATCH, pwb2);
ATOMICRELEASE(pcpWBEvt2);
}
if (pcpTopWBEvt2)
{
DoInvokeParamHelper(punk, pcpTopWBEvt2, NULL, NULL, dispidPrintEvent, 1,
VT_DISPATCH, pwb2);
ATOMICRELEASE(pcpTopWBEvt2);
}
}
/*******************************************************************
NAME: FireEvent_UpdatePageStatus
SYNOPSIS: Fires a UpdatePageStatus (DISPID_UPDATEPAGESTATUS)
event to container
if there are any advise sinks
********************************************************************/
void FireEvent_UpdatePageStatus(IUnknown* punk, IWebBrowser2* pwb2, DWORD nPage, BOOL fDone)
{
// if we don't have any sinks, then there's nothing to do. we intentionally
// ignore errors here.
IConnectionPoint* pcpTopWBEvt2 = NULL;
IConnectionPoint* pcpWBEvt2 = NULL;
// Fire the event off the parent and top-level frames.
//
GetTopWBConnectionPoints(punk, NULL, &pcpTopWBEvt2);
GetWBConnectionPoints(punk, NULL, &pcpWBEvt2);
VARIANT vnPage = {0};
V_VT(&vnPage) = VT_I4;
V_I4(&vnPage) = nPage;
VARIANT vfDone = {0};
V_VT(&vfDone) = VT_BOOL;
V_BOOL(&vfDone) = fDone;
// Fire the event to the parent first and then the top-level object.
//
if (pcpWBEvt2)
{
DoInvokeParamHelper(punk, pcpWBEvt2, NULL, NULL, DISPID_UPDATEPAGESTATUS, 3,
VT_DISPATCH, pwb2,
VT_VARIANT|VT_BYREF, &vnPage,
VT_VARIANT|VT_BYREF, &vfDone);
ATOMICRELEASE(pcpWBEvt2);
}
if (pcpTopWBEvt2)
{
DoInvokeParamHelper(punk, pcpTopWBEvt2, NULL, NULL, DISPID_UPDATEPAGESTATUS, 3,
VT_DISPATCH, pwb2,
VT_VARIANT|VT_BYREF, &vnPage,
VT_VARIANT|VT_BYREF, &vfDone);
ATOMICRELEASE(pcpTopWBEvt2);
}
}
/*******************************************************************
NAME: FireEvent_PrivacyImpactedStateChange
SYNOPSIS: Fires the privacy PrivacyImpactedStateChange event
to container if there are any advise sinks
********************************************************************/
void FireEvent_PrivacyImpactedStateChange(IUnknown* punk, BOOL bPrivacyImpacted)
{
// if we don't have any sinks, then there's nothing to do. we intentionally
// ignore errors here.
IConnectionPoint* pcpTopWBEvt2 = NULL;
//
// Typically most events fire at the frame or both at frame and top level
// Since we want to fire at the top level only we just call
// GetWBConnectionPoints instead of GetTopWBConnectionPoints here
// since we always get passed in the punk for the top level
// GetTopWBConnectionPoints returns the event interfaces ONLY
// in a frameset scenario anyway.
//
GetWBConnectionPoints(punk, NULL, &pcpTopWBEvt2);
if (pcpTopWBEvt2)
{
DoInvokeParamHelper(punk, pcpTopWBEvt2, NULL, NULL, DISPID_PRIVACYIMPACTEDSTATECHANGE, 1,
VT_BOOL, bPrivacyImpacted);
ATOMICRELEASE(pcpTopWBEvt2);
}
}
/*******************************************************************
NAME: FireEvent_NewWindow
SYNOPSIS: Fires an NewWindow (DISPID_NEWWINDOW) event to container
if there are any advise sinks
NOTES: If the container wants to handle new window creation itself,
pfProcessed is filled in with TRUE on exit and we should not
create a new window ourselves.
********************************************************************/
void FireEvent_NewWindow(IUnknown* punk, HWND hwnd,
LPCITEMIDLIST pidl,LPWSTR pwzLocation,
DWORD dwFlags,LPTSTR pszFrameName,LPBYTE pPostData,
DWORD cbPostData,LPTSTR pszHeaders,BOOL * pfProcessed)
{
LBSTR::CString strPath;
GetEventURL(pidl, strPath);
*pfProcessed = FALSE;
IEDDE_BeforeNavigate(strPath, pfProcessed);
if (*pfProcessed)
return;
// We fire [Frame]NewWindow off the top frame only
//
// NOTE: This will break anyone watching navigations within a frameset...
// Do we care?
//
IConnectionPoint *pccp;
DISPID dispid = 0; // init to suppress bogus C4701 warning
if (S_OK == GetTopWBConnectionPoints(punk, &pccp, NULL))
dispid = DISPID_FRAMENEWWINDOW;
else if (S_OK == GetWBConnectionPoints(punk, &pccp, NULL))
dispid = DISPID_NEWWINDOW;
if (pccp)
{
BSTR bstrFrameName, bstrHeaders;
VARIANTARG vaPostData;
AllocEventStuff(pszFrameName, &bstrFrameName, pszHeaders, &bstrHeaders, pPostData, cbPostData, &vaPostData);
if (pidl != NULL)
{
// call DoInvokeParam to package up these parameters and call
// IDispatch::Invoke on the container.
DoInvokeParamHelper(punk, pccp, pfProcessed, NULL, dispid, 6,
VT_BSTR, strPath, // URL
VT_I4, dwFlags, // flags
VT_BSTR, bstrFrameName, // target frame name
VT_VARIANT | VT_BYREF, &vaPostData, // post data
VT_BSTR, bstrHeaders, // headers
VT_BOOL | VT_BYREF, pfProcessed); // BOOL * for indicating "processed"
}
FreeEventStuff(bstrFrameName, bstrHeaders, &vaPostData);
pccp->Release();
}
return;
}
void FireEvent_NewWindow2(IUnknown* punk, IUnknown** ppunkNewWindow, BOOL *pfCancel)
{
IConnectionPoint* pcpTopWBEvt2 = NULL;
IConnectionPoint* pcpWBEvt2 = NULL;
*pfCancel = FALSE;
*ppunkNewWindow = NULL;
// Fire NewWindow2 off the parent and top-level frames.
// We only fire [Frame]NewWindow off the top-level
// frame for backward compatibility.
//
GetTopWBConnectionPoints(punk, NULL, &pcpTopWBEvt2);
GetWBConnectionPoints(punk, NULL, &pcpWBEvt2);
if (pcpTopWBEvt2 || pcpWBEvt2)
{
//
// The AOL browser wants to override the behavior of "Open in New Window"
// so it opens a new AOL window instead of a new IE window. They do this by
// responding to this message by creating the AOL window and putting its
// IUnknown into *ppunkNewWindow.
// Fire the event to the parent and then the top-level window. The
// pfCancel and ppunkNewWindow returned by the parent override the ones
// returned by the top-level window.
//
if (pcpWBEvt2)
{
DoInvokeParamHelper(punk, pcpWBEvt2, pfCancel, (void **)ppunkNewWindow, DISPID_NEWWINDOW2, 2,
VT_DISPATCH|VT_BYREF, ppunkNewWindow,
VT_BOOL |VT_BYREF, pfCancel);
}
// If the parent object cancels or specifies a new window,
// don't fire the event to the top-level object.
//
if (pcpTopWBEvt2 && !*pfCancel && !*ppunkNewWindow)
{
DoInvokeParamHelper(punk, pcpTopWBEvt2, pfCancel, (void **)ppunkNewWindow, DISPID_NEWWINDOW2, 2,
VT_DISPATCH|VT_BYREF, ppunkNewWindow,
VT_BOOL |VT_BYREF, pfCancel);
}
ATOMICRELEASE(pcpWBEvt2);
ATOMICRELEASE(pcpTopWBEvt2);
}
}
void FireEvent_FileDownload(IUnknown * punk, BOOL * pfCancel, VARIANT_BOOL bDocObject)
{
IConnectionPoint * pcpWBEvt2 = NULL;
IConnectionPoint * pcpTopWBEvt2 = NULL;
*pfCancel = FALSE;
GetWBConnectionPoints(punk, NULL, &pcpWBEvt2);
GetTopWBConnectionPoints(punk, NULL, &pcpTopWBEvt2);
if (pcpWBEvt2)
{
// disp params are reverse ordered, so the additional parameter is passed first
DoInvokeParamHelper(punk, pcpWBEvt2, pfCancel, NULL, DISPID_FILEDOWNLOAD, 2,
VT_BOOL, bDocObject,
VT_BOOL | VT_BYREF, pfCancel);
}
if (pcpTopWBEvt2 && !*pfCancel)
{
// disp params are reverse ordered, so the additional parameter is passed first
DoInvokeParamHelper(punk, pcpWBEvt2, pfCancel, NULL, DISPID_FILEDOWNLOAD, 2,
VT_BOOL, bDocObject,
VT_BOOL | VT_BYREF, pfCancel);
}
ATOMICRELEASE(pcpWBEvt2);
ATOMICRELEASE(pcpTopWBEvt2);
}
void FireEvent_DoInvokeString(IExpDispSupport* peds, DISPID dispid, LPSTR psz)
{
IConnectionPoint* pccp1, * pccp2;
if (S_OK == GetWBConnectionPoints(peds, &pccp1, &pccp2))
{
// send as generic parameter to DoInvokeParam to package up
LBSTR::CString strText;
LPTSTR pstrText = strText.GetBuffer(MAX_URL_STRING);
if (strText.GetAllocLength() < MAX_URL_STRING)
{
TraceMsg(TF_WARNING, "FireEvent_DoInvokeString() - strText Allocation Failed!");
strText.Empty();
}
else
{
SHAnsiToUnicode(psz, pstrText, MAX_URL_STRING);
// Let CString class own the buffer again.
strText.ReleaseBuffer();
}
if (! strText.IsEmpty())
{
if (pccp2)
{
DoInvokeParamHelper(SAFECAST(peds, IUnknown*), pccp2, NULL, NULL, dispid, 1, VT_BSTR, strText);
}
if (pccp1)
{
DoInvokeParamHelper(SAFECAST(peds, IUnknown*), pccp1, NULL, NULL, dispid, 1, VT_BSTR, strText);
}
}
if (pccp2)
{
pccp2->Release();
}
if (pccp1)
{
pccp1->Release();
}
}
}
void FireEvent_DoInvokeStringW(IExpDispSupport* peds, DISPID dispid, LPWSTR psz)
{
IConnectionPoint* pccp1, * pccp2;
if (S_OK == GetWBConnectionPoints(peds, &pccp1, &pccp2))
{
// send as generic parameter to DoInvokeParam to package up
LBSTR::CString strText;
if (psz)
{
strText = psz;
}
else
{
strText.Empty();
}
if (pccp2)
{
DoInvokeParamHelper(SAFECAST(peds, IUnknown*), pccp2, NULL, NULL, dispid, 1, VT_BSTR, strText);
}
if (pccp1)
{
DoInvokeParamHelper(SAFECAST(peds, IUnknown*), pccp1, NULL, NULL, dispid, 1, VT_BSTR, strText);
}
if (pccp2)
{
pccp2->Release();
}
if (pccp1)
{
pccp1->Release();
}
}
}
void FireEvent_DoInvokeBstr(IUnknown* punk, DISPID dispid, BSTR bstr)
{
IConnectionPoint* pccp1, * pccp2;
if (S_OK == GetWBConnectionPoints(punk, &pccp1, &pccp2))
{
if (pccp2)
{
DoInvokeParamHelper(punk, pccp2, NULL, NULL, dispid, 1, VT_BSTR, bstr);
pccp2->Release();
}
if (pccp1)
{
DoInvokeParamHelper(punk, pccp1, NULL, NULL, dispid, 1, VT_BSTR, bstr);
pccp1->Release();
}
}
}
void FireEvent_DoInvokeDispid(IUnknown* punk, DISPID dispid)
{
IConnectionPoint *pccp1, *pccp2;
if (S_OK == GetWBConnectionPoints(punk, &pccp1, &pccp2))
{
if (pccp2)
{
DoInvokeParamHelper(punk, pccp2, NULL, NULL, dispid, 0);
pccp2->Release();
}
if (pccp1)
{
DoInvokeParamHelper(punk, pccp1, NULL, NULL, dispid, 0);
pccp1->Release();
}
}
}
void FireEvent_DoInvokeDwords(IExpDispSupport* peds, DISPID dispid, DWORD dw1,DWORD dw2)
{
IConnectionPoint *pccp1, *pccp2;
if (S_OK == GetWBConnectionPoints(peds, &pccp1, &pccp2))
{
if (pccp2)
{
DoInvokeParamHelper(SAFECAST(peds, IUnknown*), pccp2, NULL, NULL, dispid, 2, VT_I4, dw1, VT_I4, dw2);
pccp2->Release();
}
if (pccp1)
{
DoInvokeParamHelper(SAFECAST(peds, IUnknown*), pccp1, NULL, NULL, dispid, 2, VT_I4, dw1, VT_I4, dw2);
pccp1->Release();
}
}
}
void FireEvent_Quit(IExpDispSupport* peds)
{
IConnectionPoint *pccp1, *pccp2;
if (S_OK == GetWBConnectionPoints(peds, &pccp1, &pccp2))
{
if (pccp2)
{
DoInvokeParamHelper(SAFECAST(peds, IUnknown*), pccp2, NULL, NULL, DISPID_ONQUIT, 0);
pccp2->Release();
}
if (pccp1)
{
// IE3 fired the quit event incorrectly. It was supposed to
// be VT_BOOL|VT_BYREF and we were supposed to honor the return
// result and not allow the quit. It never worked that way...
DoInvokeParamHelper(SAFECAST(peds, IUnknown*), pccp1, NULL, NULL, DISPID_QUIT, 1, VT_BOOL, VARIANT_FALSE);
pccp1->Release();
}
}
}
void FireEvent_OnAdornment(IUnknown* punk, DISPID dispid, VARIANT_BOOL f)
{
VARIANTARG args[1];
IUnknown_CPContainerInvokeParam(punk, DIID_DWebBrowserEvents2,
dispid, args, 1, VT_BOOL, f);
#ifdef DEBUG
// Verify that every IExpDispSupport also supports IConnectionPointContainer
IConnectionPointContainer *pcpc;
IExpDispSupport* peds;
if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IConnectionPointContainer, &pcpc))))
{
pcpc->Release();
}
else if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IExpDispSupport, &peds))))
{
peds->Release();
AssertMsg(0, TEXT("IExpDispSupport without IConnectionPointContainer for %08x"), punk);
}
#endif
}
HRESULT CIEFrameAuto::OnInvoke(DISPID dispidMember, REFIID iid, LCID lcid, WORD wFlags, DISPPARAMS *pdispparams,
VARIANT *pVarResult, EXCEPINFO *pexcepinfo, UINT *puArgErr)
{
VARIANT_BOOL vtb = FALSE;
HRESULT hres = S_OK;
//riid is supposed to be IID_NULL always
if (IID_NULL != iid)
return DISP_E_UNKNOWNINTERFACE;
if (!(wFlags & DISPATCH_PROPERTYGET))
return E_FAIL; // Currently we only handle Gets for Ambient Properties
switch (dispidMember)
{
case DISPID_AMBIENT_OFFLINEIFNOTCONNECTED:
get_Offline(&vtb);
pVarResult->vt = VT_BOOL;
pVarResult->boolVal = vtb ? TRUE : FALSE;
break;
case DISPID_AMBIENT_SILENT:
get_Silent(&vtb);
pVarResult->vt = VT_BOOL;
pVarResult->boolVal = vtb ? TRUE : FALSE;
break;
case DISPID_AMBIENT_PALETTE:
if (_pbs)
{
HPALETTE hpal;
hres = _pbs->GetPalette(&hpal);
if (SUCCEEDED(hres))
{
pVarResult->vt = VT_HANDLE;
pVarResult->intVal = PtrToLong(hpal);
}
}
else
hres = E_FAIL;
break;
default:
hres = E_FAIL;
}
return hres;
}
// *** IExternalConnection ***
DWORD CIEFrameAuto::AddConnection(DWORD extconn, DWORD reserved)
{
TraceMsg(TF_SHDLIFE, "shd - TR CIEFrameAuto::AddConnection(%d) called _cLock(before)=%d", extconn, _cLocks);
if (extconn & EXTCONN_STRONG)
return ++_cLocks;
return 0;
}
DWORD CIEFrameAuto::ReleaseConnection(DWORD extconn, DWORD reserved, BOOL fLastReleaseCloses)
{
TraceMsg(TF_SHDLIFE, "shd - TR CIEFrameAuto::ReleaseConnection(%d,,%d) called _cLock(before)=%d", extconn, fLastReleaseCloses, _cLocks);
if (!(extconn & EXTCONN_STRONG))
return 0;
_cLocks--;
if (((_cLocks == 0) || (_cLocks == 1 && _fWindowsListMarshalled)) && fLastReleaseCloses)
{
// We could/should have the visiblity update the count of locks.
// but this is implier for now.
VARIANT_BOOL fVisible;
get_Visible(&fVisible);
if (!fVisible)
{
HWND hwnd = _GetHWND();
//
// Notice that we close it only if that's the top level browser
// to avoid closing a hidden WebBrowserOC by mistake.
//
if (hwnd && _psbTop == _psb && !IsNamedWindow(hwnd, c_szShellEmbedding))
{
// The above test is necessary but not sufficient to determine if the item we're looking
// at is the browser frame or the WebBrowserOC.
TraceMsg(TF_SHDAUTO, "CIEFrameAuto::ReleaseConnection posting WM_CLOSE to %x", hwnd);
PostMessage(hwnd, WM_CLOSE, 0, 0);
}
}
}
return _cLocks;
}
HRESULT CIEFrameAuto::_BrowseObject(LPCITEMIDLIST pidl, UINT wFlags)
{
if (_psb)
return _psb->BrowseObject(pidl, wFlags);
return E_FAIL;
}
// return interface for riid via pct->Exec(&CGID_ShellDocView, SHDVID_GETPENDINGOBJECT...)
HRESULT ExecPending(IOleCommandTarget *pct, REFIID riid, void **ppvoid, VARIANT *pvarargIn)
{
HRESULT hres = E_FAIL;
VARIANT varOut;
VariantInit(&varOut);
hres = pct->Exec(&CGID_ShellDocView, SHDVID_GETPENDINGOBJECT, 0, pvarargIn, &varOut);
if (SUCCEEDED(hres))
{
if (varOut.vt == VT_UNKNOWN && varOut.punkVal)
{
hres = varOut.punkVal->QueryInterface(riid, ppvoid);
// Avoid oleaut for this common and known case
varOut.punkVal->Release();
return hres;
}
else hres = E_FAIL;
}
VariantClearLazy(&varOut);
return hres;
}
// returns URL for pending shell view iff there is one and there is NOT an
// active view. result returned in VT_BSTR variant
HRESULT CIEFrameAuto::_QueryPendingUrl(VARIANT *pvarResult)
{
HRESULT hres = E_FAIL;
if (_psb)
{
IShellView *psv;
if (SUCCEEDED(_psb->QueryActiveShellView(&psv)))
{
SAFERELEASE(psv);
}
else
{
IOleCommandTarget *pct;
// Use ExecPending to get IOleCommandTarget on pending shell view
hres = ExecPending(_pmsc, IID_PPV_ARG(IOleCommandTarget, &pct), NULL);
if (SUCCEEDED(hres))
{
// Use Exec to get URL corresponding to pending shell view
hres = pct->Exec(&CGID_ShellDocView, SHDVID_GETPENDINGURL, 0, NULL, pvarResult);
pct->Release();
}
}
}
return hres;
}
HRESULT CIEFrameAuto::_QueryPendingDelegate(IDispatch **ppDisp, VARIANT *pvarargIn)
{
HRESULT hres = E_FAIL;
*ppDisp = NULL;
if (_psb)
{
if (_pmsc)
{
IOleCommandTarget *pct;
// Use ExecPending to get IOleCommandTarget of pending shell view
hres = ExecPending(_pmsc, IID_PPV_ARG(IOleCommandTarget, &pct), pvarargIn);
if (SUCCEEDED(hres))
{
// Use ExecPending to get IDispatch of DocObject in pending shell view
hres = ExecPending(pct, IID_PPV_ARG(IDispatch, ppDisp), NULL);
pct->Release();
}
}
}
return hres;
}
// Gets IDispath of either the DocObject of the active shell view or, if there
// isn't an active shell view, but there is a pending shell view, ask for it's
// DocObject. If necessary, one will be created on the fly
HRESULT CIEFrameAuto::_QueryDelegate(IDispatch **ppDisp)
{
HRESULT hres = E_FAIL;
IShellView *psv;
*ppDisp = NULL;
if (_psb)
{
if (SUCCEEDED(_psb->QueryActiveShellView(&psv)) && psv)
{
ITargetContainer *ptgcActive;
HRESULT hrLocal;
LPOLESTR pwzFrameSrc;
hres = SafeGetItemObject(psv, SVGIO_BACKGROUND, IID_PPV_ARG(IDispatch, ppDisp));
// Hack to support x = window.open("","FRAME");x = window.open("URL","FRAME")
if (SUCCEEDED(hres) &&
*ppDisp &&
SUCCEEDED((*ppDisp)->QueryInterface(IID_PPV_ARG(ITargetContainer, &ptgcActive))))
{
hrLocal = ptgcActive->GetFrameUrl(&pwzFrameSrc);
if (SUCCEEDED(hrLocal) && pwzFrameSrc)
{
if (URL_SCHEME_ABOUT == GetUrlSchemeW(pwzFrameSrc))
{
IDispatch *pidPending;
VARIANT varIn;
// Pass in bool to override safety check for no active shell view
VariantInit(&varIn);
varIn.vt = VT_BOOL;
varIn.boolVal = TRUE;
hrLocal = _QueryPendingDelegate(&pidPending, &varIn);
if (SUCCEEDED(hrLocal) && pidPending)
{
(*ppDisp)->Release();
*ppDisp = pidPending;
}
VariantClearLazy(&varIn);
}
OleFree(pwzFrameSrc);
}
ptgcActive->Release();
}
psv->Release();
}
else
{
hres = _QueryPendingDelegate(ppDisp, NULL);
}
}
return hres;
}
extern HRESULT ShowHlinkFrameWindow(IUnknown *pUnkTargetHlinkFrame);
//=========================================================================
// Helper API
//=========================================================================
//
// API: HlinkFrameNavigate{NHL}
//
// This is a helper function to be called by DocObject implementations
// which are not be able to open itself as a stand-alone app (like MSHTML).
// If their IHlinkTarget::Navigate is called when the client is not set,
// they will call this API to open a separate browser window in a separate
// process (I assume that those DocObjects are all InProc DLLs).
//
// HLINK.DLL's IHlink implementation will hit this code path when
// a hyperlink object is activated in non-browser window (such as Office
// apps).
//
STDAPI HlinkFrameNavigate(DWORD grfHLNF, LPBC pbc,
IBindStatusCallback *pibsc,
IHlink* pihlNavigate,
IHlinkBrowseContext *pihlbc)
{
HRESULT hres S_OK;
IUnknown* punk = NULL;
TraceMsg(TF_COCREATE, "HlinkFrameNavigate called");
#ifdef DEBUG
DWORD dwTick = GetCurrentTime();
#endif
grfHLNF &= ~HLNF_OPENINNEWWINDOW; // Implied by CreateTargetFrame
hres = CreateTargetFrame(NULL, &punk);
#ifdef DEBUG
TraceMsg(TF_COCREATE, "HlinkFrameNavigate called CoCreate %x (took %d msec)",
hres, GetCurrentTime()-dwTick);
#endif
if (SUCCEEDED(hres))
{
IHlinkFrame* phfrm;
hres = punk->QueryInterface(IID_PPV_ARG(IHlinkFrame, &phfrm));
if (SUCCEEDED(hres))
{
if (pihlbc)
{
phfrm->SetBrowseContext(pihlbc);
grfHLNF |= HLNF_EXTERNALNAVIGATE;
}
hres = phfrm->Navigate(grfHLNF, pbc, pibsc, pihlNavigate);
if (SUCCEEDED(hres))
{
hres = ShowHlinkFrameWindow(punk);
} else {
TraceMsg(DM_ERROR, "HlinkFrameNavigate QI(InternetExplorer) failed (%x)", hres);
}
TraceMsg(TF_SHDNAVIGATE, "HlinkFrameNavigate phfrm->Navigate returned (%x)", hres);
phfrm->Release();
} else {
TraceMsg(DM_ERROR, "HlinkFrameNavigate QI(IHlinkFrame) failed (%x)", hres);
}
punk->Release();
} else {
TraceMsg(DM_ERROR, "HlinkFrameNavigate CoCreateInstance failed (%x)", hres);
}
return hres;
}
STDAPI HlinkFrameNavigateNHL(DWORD grfHLNF, LPBC pbc,
IBindStatusCallback *pibsc,
LPCWSTR pszTargetFrame,
LPCWSTR pszUrl,
LPCWSTR pszLocation)
{
HRESULT hres S_OK;
IUnknown* punk = NULL;
#define MAX_CONTENTTYPE MAX_PATH // This is a good size.
TraceMsg(TF_COCREATE, "HlinkFrameNavigateNHL called");
#ifdef DEBUG
DWORD dwTick = GetCurrentTime();
#endif
// This should be more general, but we're punting the FILE: case for IE 4
// unless the extension is .htm or .html (all that Netscape 3.0 registers for)
// we'll go with ShellExecute if IE is not the default browser. NOTE:
// this means POST will not be supported and pszTargetFrame will be ignored
// we don't shellexecute FILE: url's because URL.DLL doesn't give a security
// warning for .exe's etc.
if ((!IsIEDefaultBrowser()))
{
WCHAR wszUrl[INTERNET_MAX_URL_LENGTH];
CHAR aszUrl[INTERNET_MAX_URL_LENGTH];
int chUrl;
HINSTANCE hinstRet;
LPWSTR pwszExt;
BOOL bSafeToExec = TRUE;
DWORD dwCodePage = 0;
if (pibsc)
{
DWORD dw = 0;
BINDINFO bindinfo = { sizeof(BINDINFO) };
HRESULT hrLocal = pibsc->GetBindInfo(&dw, &bindinfo);
if (SUCCEEDED(hrLocal))
{
dwCodePage = bindinfo.dwCodePage;
ReleaseBindInfo(&bindinfo);
}
}
if (!dwCodePage)
{
dwCodePage = CP_ACP;
}
chUrl = lstrlenW(pszUrl);
pwszExt = PathFindExtensionW(pszUrl);
if (URL_SCHEME_FILE == GetUrlSchemeW(pszUrl))
{
WCHAR wszContentType[MAX_CONTENTTYPE];
DWORD dwSize = ARRAYSIZE(wszContentType);
bSafeToExec = FALSE;
// Get Content type.
if (SUCCEEDED(AssocQueryString(0, ASSOCSTR_CONTENTTYPE, pwszExt, NULL, wszContentType, &dwSize)))
{
bSafeToExec = 0 == StrCmpIW(wszContentType, L"text/html");
}
}
if (bSafeToExec)
{
StrCpyNW(wszUrl, pszUrl, ARRAYSIZE(wszUrl));
// don't attempt unless we have at least enough for '#' {any} '\0'
// NOTE: # is included in pszLocation
if (pszLocation && *pszLocation && ARRAYSIZE(wszUrl) - chUrl >= 3)
{
StrCpyNW(&wszUrl[chUrl], pszLocation, ARRAYSIZE(wszUrl) - chUrl - 1);
}
//
// UNICODE - should this get changed to wchar?
//
// finally we will get the string in the native codepage
SHUnicodeToAnsiCP(dwCodePage, wszUrl, aszUrl, ARRAYSIZE(aszUrl));
hinstRet = ShellExecuteA(NULL, NULL, aszUrl, NULL, NULL, SW_SHOWNORMAL);
return ((UINT_PTR)hinstRet) <= 32 ? E_FAIL:S_OK;
}
}
grfHLNF &= ~HLNF_OPENINNEWWINDOW; // Implied by CreateTargetFrame
hres = CreateTargetFrame(pszTargetFrame, &punk);
#ifdef DEBUG
TraceMsg(TF_COCREATE, "HlinkFrameNavigateNHL called CoCreate %x (took %d msec)", hres, GetCurrentTime()-dwTick);
#endif
if (SUCCEEDED(hres))
{
ITargetFramePriv *ptgfp;
hres = punk->QueryInterface(IID_PPV_ARG(ITargetFramePriv, &ptgfp));
if (SUCCEEDED(hres))
{
hres = ptgfp->NavigateHack(grfHLNF, pbc, pibsc, NULL, pszUrl, pszLocation);
if (SUCCEEDED(hres))
{
hres = ShowHlinkFrameWindow(punk);
}
else
{
TraceMsg(DM_ERROR, "HlinkFrameNavigate QI(InternetExplorer) failed (%x)", hres);
}
TraceMsg(TF_SHDNAVIGATE, "HlinkFrameNavigate phfrm->Navigate returned (%x)", hres);
ptgfp->Release();
}
else
{
TraceMsg(DM_ERROR, "HlinkFrameNavigate QI(IHlinkFrame) failed (%x)", hres);
}
punk->Release();
}
else
{
TraceMsg(DM_ERROR, "HlinkFrameNavigate CoCreateInstance failed (%x)", hres);
}
return hres;
}
CIEFrameClassFactory* g_pcfactory = NULL;
CIEFrameClassFactory* g_pcfactoryShell = NULL;
//
// This function is called when the first browser window is being created.
// punkAuto is non-NULL if and only if the browser is started as the result
// of CoCreateInstance.
//
void IEInitializeClassFactoryObject(IUnknown* punkAuto)
{
ASSERT(g_pcfactory==NULL);
ASSERT(g_pcfactoryShell==NULL);
AssertParking();
// We don't want to register this local server stuff for the shell process
// if we are in browse in new process and this is the Explorer process.
if (!IsBrowseNewProcessAndExplorer())
{
g_pcfactory = new CIEFrameClassFactory(punkAuto, CLSID_InternetExplorer, COF_IEXPLORE);
}
g_pcfactoryShell = new CIEFrameClassFactory(NULL, CLSID_ShellBrowserWindow, COF_SHELLFOLDERWINDOW);
}
//
// This function is called when the primaty thread is going away.
// It revokes the class factory object and release it.
//
void IERevokeClassFactoryObject(void)
{
AssertParking();
if (g_pcfactory)
{
g_pcfactory->Revoke();
ATOMICRELEASE(g_pcfactory);
}
if (g_pcfactoryShell)
{
g_pcfactoryShell->Revoke();
ATOMICRELEASE(g_pcfactoryShell);
}
}
//
// This function is called when the first browser window is being destroyed.
// It will remove the registered automation object (via IEInitializeClass...)
// to accidentally return an automation object to closed window.
//
void IECleanUpAutomationObject()
{
if (g_pcfactory)
g_pcfactory->CleanUpAutomationObject();
if (g_pcfactoryShell)
g_pcfactoryShell->CleanUpAutomationObject();
}
void IEOnFirstBrowserCreation(IUnknown* punk)
{
// For the desktop case, we DON'T have a g_tidParking set
// and we don't need one, so this assert is bogus in that
// case. But it's probably checking something valid, so
// I made the assert not fire in the desktop case. Unfortunately
// this also makes it not fire in most other cases that it
// checks, but at least it will check a few things (if automated)
//
ASSERT(g_tidParking == GetCurrentThreadId() || !punk);
// If automation, now is good time to register ourself...
if (g_fBrowserOnlyProcess)
IEInitializeClassFactoryObject(punk);
//
// Tell IEDDE that automation services are now available.
//
IEDDE_AutomationStarted();
}
HRESULT CoCreateNewIEWindow(DWORD dwClsContext, REFIID riid, void **ppvunk)
{
// QFE 2844 -- We don't want to create a new window as a local
// server off of the registered class object. Simply create
// the window in a new thread by a direct createinstance.
if (dwClsContext & CLSCTX_INPROC_SERVER)
{
HRESULT hr = REGDB_E_CLASSNOTREG;
IClassFactory *pcf = NULL;
*ppvunk = NULL;
if (g_pcfactory &&
SUCCEEDED(hr = g_pcfactory->QueryInterface(IID_PPV_ARG(IClassFactory, &pcf))))
{
hr = pcf->CreateInstance(NULL, riid, ppvunk);
pcf->Release();
}
if (SUCCEEDED(hr))
{
return hr;
}
else
{
// Try other contexts via CoCreateInstance since inproc failed.
dwClsContext &= ~CLSCTX_INPROC_SERVER;
if (!dwClsContext) {
return hr;
}
}
}
return CoCreateInstance(CLSID_InternetExplorer, NULL, dwClsContext, riid, ppvunk);
}
SAFEARRAY * MakeSafeArrayFromData(LPCBYTE pData,DWORD cbData)
{
if (!pData || 0 == cbData)
return NULL; // nothing to do
// create a one-dimensional safe array
SAFEARRAY *psa = SafeArrayCreateVector(VT_UI1,0,cbData);
if (psa)
{
// copy data into the area in safe array reserved for data
// Note we party directly on the pointer instead of using locking/
// unlocking functions. Since we just created this and no one
// else could possibly know about it or be using it, this is OK.
ASSERT(psa->pvData);
memcpy(psa->pvData,pData,cbData);
}
return psa;
}
/******************************************************************************
Helper Functions
******************************************************************************/
/******************************************************************************
Safe version of the Win32 SysAllocStringLen() function. Allows you to
pass in a string (pStr) that is smaller than the desired BSTR (len).
******************************************************************************/
BSTR SafeSysAllocStringLen(const WCHAR *pStr, const unsigned int len)
{
// SysAllocStringLen allocates len + 1
BSTR pNewStr = SysAllocStringLen(NULL, len);
if (pStr && pNewStr)
{
// StrCpyNW always null terminates so we need to copy len+1
StrCpyNW(pNewStr, pStr, len + 1);
}
return pNewStr;
}
BSTR SysAllocStringFromANSI(const char *pStr, int size = -1)
{
if (!pStr)
return 0;
if (size < 0)
size = lstrlenA(pStr);
// Allocates size + 1
BSTR bstr = SysAllocStringLen(NULL, size);
if (bstr)
{
if (!MultiByteToWideChar(CP_ACP, 0, pStr, -1, bstr, size + 1))
{
SysFreeString(bstr);
bstr = 0;
}
}
return bstr;
}
HRESULT GetDelegateOnIDispatch(IDispatch* pdisp, const DISPID delegateID, IDispatch ** const ppDelegate)
{
HRESULT hres;
if (!pdisp || ! ppDelegate)
return E_POINTER;
DISPPARAMS dispparams = {0};
VARIANT VarResult;
VariantInit(&VarResult);
hres = pdisp->Invoke( delegateID,
IID_NULL,
0,
DISPATCH_PROPERTYGET,
&dispparams,
&VarResult,
NULL,
NULL);
if (SUCCEEDED(hres))
{
if (VarResult.vt == VT_DISPATCH && VarResult.pdispVal)
{
*ppDelegate = VarResult.pdispVal;
(*ppDelegate)->AddRef();
}
else
{
// Temporary hack (I think) until Trident always returns IDispatch
if (VarResult.pdispVal && VarResult.vt == VT_UNKNOWN)
hres = VarResult.pdispVal->QueryInterface(IID_PPV_ARG(IDispatch, ppDelegate));
else
hres = E_FAIL;
}
VariantClearLazy(&VarResult);
}
return hres;
}
HRESULT GetRootDelegate(CIEFrameAuto* pauto, IDispatch ** const ppRootDelegate)
{
IDispatch *pdiDocObject;
HRESULT hres;
if (!pauto || !ppRootDelegate)
return E_POINTER;
// Get the IHTMLWindow2 of docobject in our frame. Note: if this is cached
// you must put glue into docobjhost to release the cache when deactivating
// view.
hres = pauto->_QueryDelegate(&pdiDocObject);
if (SUCCEEDED(hres))
{
hres = GetDelegateOnIDispatch(pdiDocObject, DISPID_WINDOWOBJECT, ppRootDelegate);
pdiDocObject->Release();
}
return hres;
}
HRESULT GetWindowFromUnknown(IUnknown *pUnk, IHTMLWindow2 **pWinOut)
{
return IUnknown_QueryService(pUnk, SID_SOmWindow, IID_PPV_ARG(IHTMLWindow2, pWinOut));
}
/******************************************************************************
Automation Stub Object
******************************************************************************/
CIEFrameAuto::CAutomationStub::CAutomationStub(DISPID minDispid, DISPID maxDispid, BOOL fOwnDefaultDispid) :
_MinDispid(minDispid), _MaxDispid(maxDispid), _fOwnDefaultDispid(fOwnDefaultDispid)
{
ASSERT(!_pInterfaceTypeInfo2);
ASSERT(!_pCoClassTypeInfo2);
ASSERT(!_pAuto);
ASSERT(!_pInstance);
ASSERT(!_fLoaded);
}
CIEFrameAuto::CAutomationStub::~CAutomationStub()
{
SAFERELEASE(_pInterfaceTypeInfo2);
SAFERELEASE(_pCoClassTypeInfo2);
}
HRESULT CIEFrameAuto::CAutomationStub::Init(void *instance, REFIID iid, REFIID clsid, CIEFrameAuto *pauto)
{
if (!pauto || !instance)
return E_POINTER;
_iid = iid;
_clsid = clsid;
// Don't need to AddRef this since our lifetime is controled by CIEFrameAuto
_pAuto = pauto;
_pInstance = instance;
return S_OK;
}
STDMETHODIMP CIEFrameAuto::CAutomationStub::QueryInterface(REFIID riid, void **ppv)
{
*ppv = NULL;
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_IDispatch) ||
IsEqualIID(riid, IID_IDispatchEx))
{
*ppv = SAFECAST(this, IDispatchEx*);
}
else if (IsEqualIID(riid, IID_IProvideClassInfo))
{
*ppv = SAFECAST(this, IProvideClassInfo*);
}
else
{
return _InternalQueryInterface(riid, ppv);
}
AddRef();
return S_OK;
}
ULONG CIEFrameAuto::CAutomationStub::AddRef(void)
{
ASSERT(_pAuto);
return _pAuto->AddRef();
}
ULONG CIEFrameAuto::CAutomationStub::Release(void)
{
ASSERT(_pAuto);
return _pAuto->Release();
}
/******************************************************************************
// bradsch 11/8/96
// I don't think typeinfo for the object implemented in the browser should
// live in MSHTML. It should be moved to shdocvw. For now so we don't have
// to worry about hard coded LIBIDs and changing versions this methods gets
// typeinfo from the delegate that lives in Trident. In cases where we have
// not delegate this method tries to load typeinfo directly from MSHTML.
******************************************************************************/
HRESULT CIEFrameAuto::CAutomationStub::ResolveTypeInfo2()
{
ASSERT(!_pInterfaceTypeInfo2);
ASSERT(!_pCoClassTypeInfo2);
ASSERT(_pAuto);
// Only try once.
_fLoaded = TRUE;
// Have we computed MatchExactGetIDsOfNames yet?
if (!IEFrameAuto()->_hinstMSHTML)
{
// No, so look for helper function in mshtml.dll
IEFrameAuto()->_hinstMSHTML = LoadLibrary(TEXT("mshtml.dll"));
if (IEFrameAuto()->_hinstMSHTML && !IEFrameAuto()->_pfnMEGetIDsOfNames)
{
IEFrameAuto()->_pfnMEGetIDsOfNames =
(PFN_MatchExactGetIDsOfNames)GetProcAddress(IEFrameAuto()->_hinstMSHTML, "MatchExactGetIDsOfNames");
}
}
ITypeLib *pTypeLib = 0;
IDispatch *pDisp = 0;
HRESULT hr = GetRootDelegate(_pAuto, &pDisp);
if (SUCCEEDED(hr))
{
UINT supported;
hr = pDisp->GetTypeInfoCount(&supported);
if (SUCCEEDED(hr) && supported)
{
ITypeInfo *pTypeInfo = 0;
hr = pDisp->GetTypeInfo(0, 0, &pTypeInfo);
if (SUCCEEDED(hr))
{
UINT index;
hr = pTypeInfo->GetContainingTypeLib(&pTypeLib, &index);
SAFERELEASE(pTypeInfo);
}
}
SAFERELEASE(pDisp);
}
if (FAILED(hr))
{
// If, for some reason, we failed to load the type library this way,
// load the type library directly out of MSHTML's resources.
// We shouldn't hard code this...
hr = LoadTypeLib(L"mshtml.tlb", &pTypeLib);
}
if (FAILED(hr))
return hr;
ITypeInfo *pTopTypeInfo = 0;
ITypeInfo *pTmpTypeInfo = 0;
ITypeInfo *pCoClassTypeInfo = 0;
// Get the coclass TypeInfo
hr = pTypeLib->GetTypeInfoOfGuid(_clsid, &pCoClassTypeInfo);
if (SUCCEEDED(hr))
hr = pCoClassTypeInfo->QueryInterface(IID_ITypeInfo2, (void**)&_pCoClassTypeInfo2);
if (FAILED(hr))
goto Exit;
// get the TKIND_INTERFACE
hr = pTypeLib->GetTypeInfoOfGuid(_iid, &pTopTypeInfo);
if (SUCCEEDED(hr))
{
HREFTYPE hrt;
// get the TKIND_INTERFACE from a TKIND_DISPATCH
hr = pTopTypeInfo->GetRefTypeOfImplType(0xffffffff, &hrt);
if (SUCCEEDED(hr))
{
// get the typeInfo associated with the href
hr = pTopTypeInfo->GetRefTypeInfo(hrt, &pTmpTypeInfo);
if (SUCCEEDED(hr))
hr = pTmpTypeInfo->QueryInterface(IID_ITypeInfo2, (void**)&_pInterfaceTypeInfo2);
}
}
Exit:
SAFERELEASE(pCoClassTypeInfo);
SAFERELEASE(pTmpTypeInfo);
SAFERELEASE(pTopTypeInfo);
SAFERELEASE(pTypeLib);
return hr;
}
// *** IDispatch members ***
HRESULT CIEFrameAuto::CAutomationStub::GetTypeInfoCount(UINT *typeinfo)
{
if (!typeinfo)
return E_POINTER;
if (!_fLoaded)
ResolveTypeInfo2();
*typeinfo = _pInterfaceTypeInfo2 ? 1 : 0;
return S_OK;
}
HRESULT CIEFrameAuto::CAutomationStub::GetTypeInfo(UINT itinfo, LCID, ITypeInfo **typeinfo)
{
if (!typeinfo)
return E_POINTER;
*typeinfo = NULL;
if (0 != itinfo)
return TYPE_E_ELEMENTNOTFOUND;
if (!_fLoaded)
{
HRESULT hr = ResolveTypeInfo2();
if (FAILED(hr))
return hr;
}
if (_pInterfaceTypeInfo2)
{
*typeinfo = _pInterfaceTypeInfo2;
_pInterfaceTypeInfo2->AddRef();
}
return *typeinfo ? S_OK : E_FAIL;
}
HRESULT CIEFrameAuto::CAutomationStub::GetIDsOfNames(
REFIID riid,
OLECHAR **rgszNames,
UINT cNames,
LCID lcid,
DISPID *rgdispid)
{
// Since the majority of script operates on built in (non-expando) properties
// This implementation should be faster than simply passing all lookups to
// the delegate.
// Handle it if we can. It is OK to return a DISPID for a method/property
// that is implemented by Trident. We will simply pass it through in Invoke
if (!_fLoaded)
ResolveTypeInfo2();
if (!_pInterfaceTypeInfo2)
return TYPE_E_CANTLOADLIBRARY;
HRESULT hr = _pInterfaceTypeInfo2->GetIDsOfNames(rgszNames, cNames, rgdispid);
if (FAILED(hr))
{
IDispatchEx *delegate = 0;
hr = _GetIDispatchExDelegate(&delegate);
if (SUCCEEDED(hr))
{
hr = delegate->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
delegate->Release();
}
}
return hr;
}
HRESULT CIEFrameAuto::CAutomationStub::InvokeEx (DISPID dispidMember,
LCID lcid,
WORD wFlags,
DISPPARAMS * pdispparams,
VARIANT * pvarResult,
EXCEPINFO * pexcepinfo,
IServiceProvider *pSrvProvider)
{
HRESULT hr;
if (dispidMember == DISPID_SECURITYCTX)
{
//
// Return the url of the document as a bstr.
//
if (pvarResult)
{
hr = _pAuto->_QueryPendingUrl(pvarResult);
if (SUCCEEDED(hr))
return S_OK;
}
}
if ((dispidMember != DISPID_SECURITYCTX) &&
((dispidMember >= _MinDispid && dispidMember <= _MaxDispid) ||
(_fOwnDefaultDispid && DISPID_VALUE == dispidMember)))
{
BOOL fNamedDispThis = FALSE;
VARIANTARG *rgOldVarg = NULL; // init to suppress bogus C4701 warning
DISPID *rgdispidOldNamedArgs = NULL; // init to suppress bogus C4701 warning
if (!_fLoaded)
ResolveTypeInfo2();
if (!_pInterfaceTypeInfo2)
return TYPE_E_CANTLOADLIBRARY;
// Any invoke call from a script engine might have the named argument
// DISPID_THIS. If so then we'll not include this argument in the
// list of parameters because oleaut doesn't know how to deal with this
// argument.
if (pdispparams->cNamedArgs && (pdispparams->rgdispidNamedArgs[0] == DISPID_THIS))
{
fNamedDispThis = TRUE;
pdispparams->cNamedArgs--;
pdispparams->cArgs--;
rgOldVarg = pdispparams->rgvarg;
rgdispidOldNamedArgs = pdispparams->rgdispidNamedArgs;
pdispparams->rgvarg++;
pdispparams->rgdispidNamedArgs++;
if (pdispparams->cNamedArgs == 0)
pdispparams->rgdispidNamedArgs = NULL;
if (pdispparams->cArgs == 0)
pdispparams->rgvarg = NULL;
}
// It belongs to us. Use the typelib to call our method.
hr = _pInterfaceTypeInfo2->Invoke(_pInstance,
dispidMember,
wFlags,
pdispparams,
pvarResult,
pexcepinfo,
NULL);
// Replace the named DISPID_THIS argument.
if (fNamedDispThis)
{
pdispparams->cNamedArgs++;
pdispparams->cArgs++;
pdispparams->rgvarg = rgOldVarg;
pdispparams->rgdispidNamedArgs = rgdispidOldNamedArgs;
}
}
else
{
// Pass it along
IDispatchEx *delegate = 0;
hr = _GetIDispatchExDelegate(&delegate);
if (SUCCEEDED(hr))
{
hr = delegate->InvokeEx(dispidMember,
lcid,
wFlags,
pdispparams,
pvarResult,
pexcepinfo,
pSrvProvider);
delegate->Release();
}
else
{
// If we're hosting a non-Trident DocObject, we can get here trying to answer an
// Invoke on the Security Context. This can cause cross-frame access to fail,
// even when we want it to succeed. If we pass back the URL of the active view,
// then Trident can do the proper cross-frame access checking.
//
if (dispidMember == DISPID_SECURITYCTX)
{
if (_pAuto && _pAuto->_psb) // Check them both for paranoia.
{
IShellView *psv;
if (SUCCEEDED(_pAuto->_psb->QueryActiveShellView(&psv)))
{
IOleCommandTarget *pct;
if (SUCCEEDED(psv->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pct))))
{
// The name of the ID is misleading -- it really returns the URL of the view. It was
// invented for Pending views, but works just as well for active views.
//
hr = pct->Exec(&CGID_ShellDocView, SHDVID_GETPENDINGURL, 0, NULL, pvarResult);
SAFERELEASE(pct);
}
SAFERELEASE(psv);
}
}
}
}
}
return hr;
}
HRESULT CIEFrameAuto::CAutomationStub::Invoke(
DISPID dispidMember,
REFIID,
LCID lcid,
WORD wFlags,
DISPPARAMS *pdispparams,
VARIANT *pvarResult,
EXCEPINFO *pexcepinfo,
UINT *)
{
return InvokeEx (dispidMember, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, NULL);
}
// *** IDispatchEx members ***
STDMETHODIMP CIEFrameAuto::CAutomationStub::GetDispID(
BSTR bstrName,
DWORD grfdex,
DISPID *pid)
{
HRESULT hr;
if (!_fLoaded)
ResolveTypeInfo2();
if (!_pInterfaceTypeInfo2)
return TYPE_E_CANTLOADLIBRARY;
// Do a case sensitive compare?
if (IEFrameAuto()->_pfnMEGetIDsOfNames)
{
// Case sensitve GetIDsOfNames.
hr = (IEFrameAuto()->_pfnMEGetIDsOfNames)(_pInterfaceTypeInfo2,
IID_NULL,
&bstrName,
1, 0, pid,
grfdex & fdexNameCaseSensitive);
}
else
{
hr = _pInterfaceTypeInfo2->GetIDsOfNames(&bstrName, 1, pid);
}
// If fails then try typelibrary.
if (FAILED(hr))
{
IDispatchEx *delegate = 0;
// Always delegate which is faster, avoids loading the typelibrary.
hr = _GetIDispatchExDelegate(&delegate);
if (SUCCEEDED(hr))
{
hr = delegate->GetDispID(bstrName, grfdex, pid);
delegate->Release();
}
}
return hr;
}
STDMETHODIMP CIEFrameAuto::CAutomationStub::DeleteMemberByName(BSTR bstr, DWORD grfdex)
{
HRESULT hr;
IDispatchEx *delegate = 0;
// Always delegate which is faster, avoids loading the typelibrary.
hr = _GetIDispatchExDelegate(&delegate);
if (SUCCEEDED(hr))
{
hr = delegate->DeleteMemberByName(bstr,grfdex);
delegate->Release();
}
return hr;
}
STDMETHODIMP CIEFrameAuto::CAutomationStub::DeleteMemberByDispID(DISPID id)
{
HRESULT hr;
IDispatchEx *delegate = 0;
// Always delegate which is faster, avoids loading the typelibrary.
hr = _GetIDispatchExDelegate(&delegate);
if (SUCCEEDED(hr))
{
hr = delegate->DeleteMemberByDispID(id);
delegate->Release();
}
return hr;
}
STDMETHODIMP CIEFrameAuto::CAutomationStub::GetMemberProperties(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
{
HRESULT hr;
IDispatchEx *delegate = 0;
// Always delegate which is faster, avoids loading the typelibrary.
hr = _GetIDispatchExDelegate(&delegate);
if (SUCCEEDED(hr))
{
hr = delegate->GetMemberProperties( id, grfdexFetch, pgrfdex);
delegate->Release();
}
return hr;
}
STDMETHODIMP CIEFrameAuto::CAutomationStub::GetMemberName(DISPID id, BSTR *pbstrName)
{
HRESULT hr;
IDispatchEx *delegate = 0;
// Always delegate which is faster, avoids loading the typelibrary.
hr = _GetIDispatchExDelegate(&delegate);
if (SUCCEEDED(hr))
{
hr = delegate->GetMemberName( id, pbstrName);
delegate->Release();
}
return hr;
}
STDMETHODIMP CIEFrameAuto::CAutomationStub::GetNextDispID(
DWORD grfdex,
DISPID id,
DISPID *pid)
{
IDispatchEx *delegate = 0;
HRESULT hr = _GetIDispatchExDelegate(&delegate);
if (SUCCEEDED(hr))
{
hr = delegate->GetNextDispID(grfdex, id, pid);
delegate->Release();
}
return hr;
}
STDMETHODIMP CIEFrameAuto::CAutomationStub::GetNameSpaceParent(IUnknown **ppunk)
{
HRESULT hr;
if (!ppunk)
{
hr = E_INVALIDARG;
goto Cleanup;
}
*ppunk = NULL;
hr = S_OK;
Cleanup:
return hr;
}
// *** IProvideClassInfo members ***
STDMETHODIMP CIEFrameAuto::CAutomationStub::GetClassInfo(ITypeInfo **typeinfo)
{
if (!typeinfo)
return E_POINTER;
if (!_fLoaded)
{
HRESULT hr = ResolveTypeInfo2();
if (FAILED(hr))
{
*typeinfo = NULL;
return hr;
}
}
*typeinfo = _pCoClassTypeInfo2;
if (*typeinfo)
{
(*typeinfo)->AddRef();
return S_OK;
}
return E_FAIL;
}
/******************************************************************************
Window Object
******************************************************************************/
// Define static variables
unsigned long CIEFrameAuto::COmWindow::s_uniqueIndex = 0;
CIEFrameAuto::COmWindow::COmWindow() :
CAutomationStub(MIN_BROWSER_DISPID, MAX_BROWSER_DISPID, FALSE)
{
ASSERT(FALSE == _fCallbackOK);
ASSERT(!_pOpenedWindow);
ASSERT(_varOpener.vt == VT_EMPTY);
ASSERT(!_dwCPCookie);
ASSERT(!_pCP);
ASSERT(!_fOnloadFired);
ASSERT(!_fIsChild);
ASSERT(!_pIntelliForms);
_fDelegateWindowOM = TRUE; // Always delegate, unless told otherwise.
}
HRESULT CIEFrameAuto::COmWindow::Init()
{
_cpWindowEvents.SetOwner(SAFECAST(SAFECAST(this, CAutomationStub*), IDispatchEx*), &DIID_HTMLWindowEvents);
CIEFrameAuto* pauto = IToClass(CIEFrameAuto, _omwin, this);
return CAutomationStub::Init(SAFECAST(this, IHTMLWindow2*), IID_IHTMLWindow2, CLSID_HTMLWindow2, pauto);
}
#ifdef NO_MARSHALLING
EXTERN_C const GUID IID_IWindowStatus;
#endif
HRESULT CIEFrameAuto::COmWindow::_InternalQueryInterface(REFIID riid, void ** const ppv)
{
ASSERT(!IsEqualIID(riid, IID_IUnknown));
if (IsEqualIID(riid, IID_IHTMLWindow2) || IsEqualIID(riid, IID_IHTMLFramesCollection2))
*ppv = SAFECAST(this, IHTMLWindow2*);
else if (IsEqualIID(riid, IID_IHTMLWindow3))
*ppv = SAFECAST(this, IHTMLWindow3*);
else if (IsEqualIID(riid, IID_ITargetNotify))
*ppv = SAFECAST(this, ITargetNotify*);
else if (IsEqualIID(riid, IID_IShellHTMLWindowSupport))
*ppv = SAFECAST(this, IShellHTMLWindowSupport*);
else if (IsEqualIID(riid, IID_IShellHTMLWindowSupport2))
*ppv = SAFECAST(this, IShellHTMLWindowSupport2*);
else if (IsEqualIID(riid, IID_IProvideMultipleClassInfo) ||
IsEqualIID(riid, IID_IProvideClassInfo2))
*ppv = SAFECAST(this, IProvideMultipleClassInfo*);
else if (IsEqualIID(riid, IID_IConnectionPointCB))
*ppv = SAFECAST(this, IConnectionPointCB*);
else if (IsEqualIID(riid, IID_IConnectionPointContainer))
*ppv = SAFECAST(this, IConnectionPointContainer*);
else if (IsEqualIID(riid, IID_IServiceProvider))
*ppv = SAFECAST(this, IServiceProvider *);
#ifdef NO_MARSHALLING
else if (IsEqualIID(riid, IID_IWindowStatus))
*ppv = SAFECAST(this, IWindowStatus *);
#endif
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
// ** IProvideMultipleClassInfo
STDMETHODIMP CIEFrameAuto::COmWindow::GetGUID(DWORD dwGuidKind, GUID* pGUID)
{
if (!pGUID)
return E_POINTER;
if (GUIDKIND_DEFAULT_SOURCE_DISP_IID == dwGuidKind)
{
*pGUID = DIID_HTMLWindowEvents;
return S_OK;
}
else
return E_INVALIDARG;
}
/******************************************************************************
Both IProvideMultipleClassInfo specific methods are passed along to Trident.
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmWindow::GetMultiTypeInfoCount(ULONG *pcti)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
IProvideMultipleClassInfo *pMCI = 0;
hr = pWindow->QueryInterface(IID_PPV_ARG(IProvideMultipleClassInfo, &pMCI));
pWindow->Release();
if (SUCCEEDED(hr))
{
hr = pMCI->GetMultiTypeInfoCount(pcti);
pMCI->Release();
}
}
return hr;
}
STDMETHODIMP CIEFrameAuto::COmWindow::GetInfoOfIndex(ULONG iti, DWORD dwFlags, ITypeInfo **pptiCoClass, DWORD *pdwTIFlags, ULONG *pcdispidReserved,IID *piidPrimary,IID *piidSource)
{
IHTMLWindow2 *pWindow;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
IProvideMultipleClassInfo *pMCI = 0;
hr = pWindow->QueryInterface(IID_PPV_ARG(IProvideMultipleClassInfo, &pMCI));
pWindow->Release();
if (SUCCEEDED(hr))
{
hr = pMCI->GetInfoOfIndex(iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
pMCI->Release();
}
}
return hr;
}
STDMETHODIMP CIEFrameAuto::COmWindow::GetDispID(BSTR bstrName, DWORD grfdex, DISPID *pid)
{
IDispatchEx *delegate;
HRESULT hr = _GetIDispatchExDelegate(&delegate);
if (SUCCEEDED(hr))
{
hr = delegate->GetDispID(bstrName, grfdex, pid);
delegate->Release();
}
else
{
return CAutomationStub::GetDispID(bstrName, grfdex, pid);
}
return hr;
}
/*****************************************************************************
IServiceProvider - this is used by mshtml as well as intelliforms in iforms.cpp
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmWindow::QueryService(REFGUID guidService, REFIID riid, void ** ppv)
{
HRESULT hr = E_NOINTERFACE;
if (!ppv)
return E_POINTER;
*ppv = NULL;
if (IsEqualGUID(guidService,IID_IHTMLWindow2))
{
return QueryInterface(riid, ppv);
}
else if (IsEqualGUID(guidService, IID_IEnumPrivacyRecords))
{
IHTMLWindow2 *pWindow = 0;
IServiceProvider * pISP = NULL;
hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->QueryInterface(IID_PPV_ARG(IServiceProvider, &pISP));
if (SUCCEEDED(hr))
{
hr = pISP->QueryService(IID_IEnumPrivacyRecords, riid, ppv);
pISP->Release();
}
pWindow->Release();
}
return hr;
}
return hr;
}
STDMETHODIMP CIEFrameAuto::COmWindow::ViewReleaseIntelliForms()
{
ReleaseIntelliForms();
return S_OK;
}
/******************************************************************************
This method is called when the document contained by the browser is being
deactivated (like when navigating to a new location). Currently we only use
this knowledge to handle event sourcing.
This method could also be used to optimize our connections to expando
implentations in the document (trident). Currently we obtain and release
the expando implementations for the Navigator, History, and Location objects
each time they are needed. ViewRelease (along with ViewActivated) would allow
us to grab and hold expando implementations until the next navigation.
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmWindow::ViewReleased()
{
UnsinkDelegate();
ReleaseIntelliForms();
BSTR bstrName = SysAllocString(STR_FIND_DIALOG_NAME);
if (bstrName)
{
VARIANT varProp;
if (SUCCEEDED(_pAuto->GetProperty(bstrName, &varProp)))
{
if ((varProp.vt == VT_DISPATCH) && (varProp.pdispVal != NULL))
{
IUnknown* pWindow = varProp.pdispVal;
VARIANT vtTmp = {0};
_pAuto->PutProperty(bstrName, vtTmp);
//(davemi) see IE5 bug 57060 for why the below line doesn't work and IDispatch must be used instead
//pWindow->close();
IDispatch * pdisp;
if (SUCCEEDED(pWindow->QueryInterface(IID_PPV_ARG(IDispatch, &pdisp))))
{
DISPID dispid;
DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
BSTR bstrClose = SysAllocString(L"close");
if (bstrClose)
{
HRESULT hr;
hr = pdisp->GetIDsOfNames(IID_NULL, &bstrClose, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if (hr == S_OK)
{
VARIANT varTmp = {0};
pdisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &varTmp, NULL, NULL);
}
SysFreeString(bstrClose);
}
pdisp->Release();
}
}
VariantClear(&varProp);
}
SysFreeString(bstrName);
}
return FireOnUnload();
}
/******************************************************************************
This method is called when the document contained by the browser is being
activated. Currently we only use this knowledge to handle event sourcing.
See comments for ViewReleased()
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmWindow::ViewActivated()
{
HRESULT hr;
// These will fail for non-trident documents which is OK.
SinkDelegate();
AttachIntelliForms();
// This call will return TRUE if either:
// - The document has reached READYSTATE_COMPLETE or
// - The document does not support the ReadyState property
// If the delegate is not complete then we will be notified of READYSTATE
// changes later. These notifications will tell use when the document is
// complete and the Onload even should be fired.
if (IsDelegateComplete())
hr = FireOnLoad();
else
hr = S_OK;
return hr;
}
STDMETHODIMP CIEFrameAuto::COmWindow::ReadyStateChangedTo(long ready_state, IShellView *psv)
{
HRESULT hr = S_OK;
// We only want to fire Onload if the ready state has changed to
// READYSTATE_COMPLETE and the view that has changed states is the
// currently active view. If the pending view has completed states
// we can ignore the notification because Onload will be fired when
// the pending view is activated. Ignoring READYSTATE changes from
// the pending view garauntees we will never fire onload early for
// the currently active view.
if ((READYSTATE_COMPLETE == ready_state) && psv)
{
IShellView * const pCurrSV = _pAuto->_GetShellView();
if (pCurrSV)
{
if (IsSameObject(pCurrSV, psv))
{
hr = FireOnLoad();
}
pCurrSV->Release();
}
}
return hr;
}
// Attach intelliforms to FORM elements on page
HRESULT CIEFrameAuto::COmWindow::AttachIntelliForms()
{
HRESULT hr = E_FAIL;
if (_pIntelliForms)
{
ReleaseIntelliForms();
_pIntelliForms = NULL;
}
IHTMLDocument2 *pDoc2=NULL;
IDispatch *pdispDoc=NULL;
_pAuto->get_Document(&pdispDoc);
if (pdispDoc)
{
pdispDoc->QueryInterface(IID_PPV_ARG(IHTMLDocument2, &pDoc2));
pdispDoc->Release();
}
if (pDoc2)
{
::AttachIntelliForms(this, NULL, pDoc2, &_pIntelliForms);
pDoc2->Release();
hr = S_OK;
}
if (_fIntelliFormsAskUser)
{
// Possibly ask user if they'd like to enable this feature
IntelliFormsDoAskUser(_pAuto->_GetHWND(), NULL); // NULL from _GetHWND() OK
_fIntelliFormsAskUser=FALSE;
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::ReleaseIntelliForms()
{
if (_pIntelliForms)
{
void *p = _pIntelliForms;
_pIntelliForms = NULL;
::ReleaseIntelliForms(p);
}
return S_OK;
}
HRESULT CIEFrameAuto::COmWindow::DestroyIntelliForms()
{
ReleaseIntelliForms();
return S_OK;
}
// Request from Intelliforms that we prompt user on next load about
// enabling the Intelliforms feature
HRESULT CIEFrameAuto::COmWindow::IntelliFormsAskUser(LPCWSTR pwszValue)
{
_fIntelliFormsAskUser = TRUE;
return S_OK;
}
/******************************************************************************
This method is called when the browser is no longer busy and we should
retry any navigate that we had to defer while it was busy.
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmWindow::CanNavigate()
{
CIEFrameAuto* pauto = IToClass(CIEFrameAuto, _omwin, this);
pauto->_omloc.RetryNavigate();
return S_OK;
}
STDMETHODIMP CIEFrameAuto::COmWindow::ActiveElementChanged(IHTMLElement * pHTMLElement)
{
return IntelliFormsActiveElementChanged(_pIntelliForms, pHTMLElement);
}
STDMETHODIMP CIEFrameAuto::COmWindow::IsGalleryMeta(BOOL bFlag)
{
// _bIsGalleryMeta = bFlag;
return S_OK;
}
HRESULT CIEFrameAuto::COmWindow::_GetIDispatchExDelegate(IDispatchEx ** const ppdelegate)
{
if (!ppdelegate)
return E_POINTER;
IDispatch *pRootDisp = 0;
HRESULT hr = GetRootDelegate(_pAuto, &pRootDisp);
if (SUCCEEDED(hr))
{
hr = pRootDisp->QueryInterface(IID_PPV_ARG(IDispatchEx, ppdelegate));
pRootDisp->Release();
}
return hr;
}
// *** IHTMLFramesCollection2 ***
HRESULT CIEFrameAuto::COmWindow::item(
/* [in] */ VARIANT *pvarIndex,
/* [retval][out] */ VARIANT *pvarResult)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->item(pvarIndex, pvarResult);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_length(long *pl)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_length(pl);
pWindow->Release();
}
return hr;
}
// *** IHTMLWindow2 ***
HRESULT CIEFrameAuto::COmWindow::get_name(BSTR *retval)
{
if (!retval)
return E_POINTER;
WCHAR *real_frame_name = 0;
WCHAR *use_frame_name = 0;
// Why doesn't GetFrameName use BSTR?
HRESULT hr = _pAuto->GetFrameName(&real_frame_name);
if (FAILED(hr))
return hr;
// If the frame's name is our special NO_NAME_NAME
// then our name is really be an empty string.
if (!real_frame_name || !StrCmpNW(real_frame_name, NO_NAME_NAME, ARRAYSIZE(NO_NAME_NAME) -1))
use_frame_name = L"";
else
use_frame_name = real_frame_name;
ASSERT(use_frame_name);
*retval = SysAllocString(use_frame_name);
if (real_frame_name)
OleFree(real_frame_name);
return *retval ? S_OK : E_OUTOFMEMORY;
}
HRESULT CIEFrameAuto::COmWindow::put_name(
/* [in] */ BSTR theName)
{
if (!theName)
return E_POINTER;
return _pAuto->SetFrameName(theName);
}
HRESULT CIEFrameAuto::COmWindow::get_parent(IHTMLWindow2 **retval)
{
if (!retval)
return E_POINTER;
HRESULT hr = E_FAIL;
IHTMLWindow2 *pWindow = NULL;
// Attempt to delegate this to the contained object.
if (_fDelegateWindowOM)
{
hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr) && pWindow)
{
hr = pWindow->get_parent(retval);
}
}
// If delegation fails, use our implementation.
if (FAILED(hr))
{
*retval = 0;
IUnknown *pUnk = 0;
hr = _pAuto->GetParentFrame(&pUnk);
// If we are already the top, GetParentFrame set pUnk to NULL
if (SUCCEEDED(hr))
{
if (pUnk)
{
hr = GetWindowFromUnknown(pUnk, retval);
pUnk->Release();
}
else
{
*retval = this;
AddRef();
}
}
}
SAFERELEASE(pWindow);
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_self(IHTMLWindow2 **retval)
{
if (!retval)
return E_POINTER;
*retval = this;
AddRef();
return S_OK;
}
HRESULT CIEFrameAuto::COmWindow::get_top(IHTMLWindow2 **retval)
{
if (!retval)
return E_POINTER;
HRESULT hr = E_FAIL;
IHTMLWindow2 *pWindow = NULL;
// Attempt to delegate this to contained object.
if (_fDelegateWindowOM)
{
hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr) && pWindow)
{
hr = pWindow->get_top(retval);
}
}
// If delegation fails, use our implementation.
if (FAILED(hr))
{
*retval = 0;
IUnknown *pUnk = 0;
// AddRef the interface to we can Release it in the while loop
ITargetFrame2 *pTfr = _pAuto;
pTfr->AddRef();
hr = pTfr->GetParentFrame(&pUnk);
// Keep calling GetParent until we fail or get a NULL (which is the top
while (SUCCEEDED(hr) && pUnk)
{
SAFERELEASE(pTfr);
hr = pUnk->QueryInterface(IID_PPV_ARG(ITargetFrame2, &pTfr));
pUnk->Release();
if (SUCCEEDED(hr))
hr = pTfr->GetParentFrame(&pUnk);
}
if (SUCCEEDED(hr))
hr = GetWindowFromUnknown(pTfr, retval);
SAFERELEASE(pTfr);
}
SAFERELEASE(pWindow);
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_window(IHTMLWindow2 **retval)
{
if (!retval)
return E_POINTER;
*retval = this;
AddRef();
return S_OK;
}
HRESULT CIEFrameAuto::COmWindow::get_frames(IHTMLFramesCollection2 **retval)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_frames(retval);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_location(IHTMLLocation **retval)
{
if (!retval)
return E_POINTER;
*retval = &_pAuto->_omloc;
(*retval)->AddRef();
return S_OK;
}
HRESULT CIEFrameAuto::COmWindow::get_navigator(IOmNavigator **retval)
{
if (!retval)
return E_POINTER;
*retval = &_pAuto->_omnav;
(*retval)->AddRef();
return S_OK;
}
HRESULT CIEFrameAuto::COmWindow::get_clientInformation(IOmNavigator **retval)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_clientInformation(retval);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_history(IOmHistory **retval)
{
if (!retval)
return E_POINTER;
*retval = &_pAuto->_omhist;
(*retval)->AddRef();
return S_OK;
}
HRESULT CIEFrameAuto::COmWindow::put_defaultStatus(BSTR statusmsg)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_defaultStatus(statusmsg);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_defaultStatus(BSTR *retval)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_defaultStatus(retval);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::put_status(BSTR statusmsg)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_status(statusmsg);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_status(BSTR *retval)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_status(retval);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::setTimeout(
/* [in] */ BSTR expression,
/* [in] */ long msec,
/* [optional] */ VARIANT *language,
/* [retval][out] */ long *timerID)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->setTimeout(expression, msec, language, timerID);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::clearTimeout(long timerID)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->clearTimeout(timerID);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::setInterval(
/* [in] */ BSTR expression,
/* [in] */ long msec,
/* [optional] */ VARIANT *language,
/* [retval][out] */ long *timerID)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->setInterval(expression, msec, language, timerID);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::clearInterval(long timerID)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->clearInterval(timerID);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::alert(BSTR message)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->alert(message);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::focus()
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->focus();
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::close()
{
IUnknown *pUnk = 0;
HRESULT hr;
if (_pAuto->_psb != _pAuto->_psbProxy) //if it's a band, just hide it
{
return IUnknown_ShowBrowserBar(_pAuto->_psbTop, CLSID_SearchBand, FALSE);
}
hr = _pAuto->GetParentFrame(&pUnk);
if (SUCCEEDED(hr))
{
if (!pUnk)
{
if (_fIsChild ||
IDYES == MLShellMessageBox(
_pAuto->_GetHWND(), // NULL from _GetHWND() OK
MAKEINTRESOURCE(IDS_CONFIRM_SCRIPT_CLOSE_TEXT),
MAKEINTRESOURCE(IDS_TITLE),
MB_YESNO | MB_ICONQUESTION))
{
_pAuto->Quit();
}
}
else
pUnk->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::blur()
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->blur();
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::scroll(long x, long y)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->scroll(x, y);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::confirm(
/* [optional] */ BSTR message,
/* [retval][out] */VARIANT_BOOL* confirmed)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->confirm(message, confirmed);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::prompt(
/* [optional] */ BSTR message,
/* [optional] */ BSTR defstr,
/* [retval][out] */ VARIANT* textdata)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->prompt(message, defstr, textdata);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_closed(VARIANT_BOOL *pl)
{
*pl = 0;
return S_OK;
}
#ifdef NO_MARSHALLING
HRESULT CIEFrameAuto::COmWindow::IsWindowActivated()
{
ASSERT(_pAuto);
BOOL fComplete = FALSE;
// Check for proper readystate support
IDispatch *pdispatch;
if (SUCCEEDED(_pAuto->get_Document(&pdispatch)))
{
VARIANTARG va;
EXCEPINFO excp;
if (SUCCEEDED(pdispatch->Invoke(DISPID_READYSTATE,
IID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYGET,
(DISPPARAMS *)&g_dispparamsNoArgs,
&va,
&excp,
NULL)))
{
if (VT_I4 == va.vt && READYSTATE_COMPLETE == va.lVal)
fComplete = TRUE;
}
pdispatch->Release();
}
return (fComplete?S_OK:S_FALSE);
}
#endif
// *** IHTMLWindow2 ***
HRESULT CIEFrameAuto::COmWindow::open(
/* [in] */ BSTR url,
/* [in] */ BSTR name,
/* [in] */ BSTR features,
/* [in] */ VARIANT_BOOL replace,
/* [out][retval] */ IHTMLWindow2 **ppomWindowResult)
{
// bradsch 11/11/96 this needs to be added back in at some point.
/*
// If the host does not support multiple windows in the same thread,
// then disable window.open
if (!g_fMultipleWindowsSupportedByHost)
{
// Hide the resulting error message from the user
if (m_pParser)
m_pParser->ShowErrors(FALSE);
return E_NOTIMPL;
}
*/
ASSERT(ppomWindowResult);
if (!ppomWindowResult)
return E_POINTER;
HRESULT hr = S_OK;
BSTR bstrUrl = NULL;
BSTR bstrWindowName = NULL;
BSTR bstrUrlAbsolute = NULL;
_OpenOptions.ReInitialize();
// Process parameter: url
if (!url)
{
// if the URL is empty, use blank.htm instead
bstrUrl = SysAllocString(L"");
}
// Process parameter: name
if (name)
{
// Make sure we have a legal name
for(int i = 0; i < lstrlenW(name); i++)
{
if (!(IsCharAlphaNumericWrapW(name[i]) || TEXT('_') == name[i]))
{
hr = E_INVALIDARG;
goto Exit;
}
}
}
// Process parameter: features
if (features && lstrlenW(features) > 0)
{
hr = _ParseOptionString(features);
if (hr)
goto Exit;
}
//
// ***TLL*** shdocvw needs to handle the replace parameter.
//
// Compute the absolute version of the URL
if (!bstrUrl || *bstrUrl)
{
if (url)
{
if (*url == EMPTY_URL)
{
bstrUrlAbsolute = SysAllocString(url);
}
else
{
bstrUrlAbsolute = _pAuto->_omloc.ComputeAbsoluteUrl(bstrUrl ? bstrUrl : url);
}
}
}
else
{
bstrUrlAbsolute = bstrUrl;
bstrUrl = NULL;
}
if (!bstrUrlAbsolute)
goto Exit;
// If a window name is not provided we need to assign it a private name
// so we do not lose track of it. If the window name is "_blank" we need
// to create a new window each time with a private name. Other portions
// of this class must be smart enough to return and an empty string when
// this private name is used.
if (!name || !*name || (*name && !StrCmpW(name, L"_blank")))
{
bstrWindowName = _GenerateUniqueWindowName();
}
// Window open state tracking
_fCallbackOK = FALSE;
*ppomWindowResult = NULL;
// Try to navigate a frame in an existing window to the url or open a new one
hr = OpenAndNavigateToURL(_pAuto,
&bstrUrlAbsolute,
bstrWindowName ? bstrWindowName : name,
SAFECAST(this, ITargetNotify*),
replace,
BOOLIFY(_pAuto->m_bSilent));
if (SUCCEEDED(hr))
{
if (_fCallbackOK)
{
*ppomWindowResult = _pOpenedWindow;
_pOpenedWindow = NULL;
ASSERT(*ppomWindowResult);
#ifdef NO_MARSHALLING
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
IWindowStatus *pws;
if ((*ppomWindowResult) && SUCCEEDED((*ppomWindowResult)->QueryInterface(IID_PPV_ARG(IWindowStatus, &pws))))
{
if (pws->IsWindowActivated() == S_OK)
{
pws->Release();
break;
}
pws->Release();
}
else
break;
}
#endif
}
// This might turn an S_FALSE into an S_OK, but is needed to keep Trident happy.
// Change this back to if (hr != S_FALSE) hr = E_FAIL,
// change BASESB.CPP to return S_FALSE instead of S_OK on a busy navigate,
// and change Trident to handle S_FALSE from window.open (RRETURN1(hr, S_FALSE));
// hr = S_OK;
}
Exit:
SAFERELEASE(_pOpenedWindow);
// Clean up the unique name if we generated it ourself
if (bstrUrl)
SysFreeString(bstrUrl);
if (bstrUrlAbsolute)
SysFreeString(bstrUrlAbsolute);
if (bstrWindowName)
SysFreeString(bstrWindowName);
return hr;
}
BSTR CIEFrameAuto::COmWindow::_GenerateUniqueWindowName()
{
WCHAR buffer[ ARRAYSIZE(NO_NAME_NAME) + 12 ];
// Choose a name the user isn't likely to typed. Need to guard
// this becuase s_uniqueIndex is a shared static variable.
ENTERCRITICAL;
unsigned long val = ++s_uniqueIndex;
LEAVECRITICAL;
StringCchPrintf(buffer, ARRAYSIZE(buffer), L"%ls%lu", NO_NAME_NAME, val);
return SysAllocString(buffer);
}
//
// Zhenbinx - Trident only talks OM Unit, not device unit.
//
class CHiResUnitConvert
{
public:
CHiResUnitConvert(IHTMLWindow2 *pWindow2)
: _pWindow2(pWindow2)
{
if (_pWindow2)
{
_pWindow2->AddRef();
}
_llogicalXDPI = _llogicalYDPI = 1;
_ldeviceXDPI = _ldeviceYDPI = 1;
_fInited = FALSE;
}
~CHiResUnitConvert()
{
if (_pWindow2)
{
_pWindow2->Release();
}
}
HRESULT Init();
LONG DeviceFromDocPixelsX(LONG cx)
{
if (!_fInited) Init();
return cx * _ldeviceXDPI / _llogicalXDPI;
}
LONG DeviceFromDocPixelsY(LONG cy)
{
if (!_fInited) Init();
return cy * _ldeviceYDPI / _llogicalYDPI;
}
private:
IHTMLWindow2 *_pWindow2;
BOOL _fInited;
LONG _llogicalXDPI;
LONG _llogicalYDPI;
LONG _ldeviceXDPI;
LONG _ldeviceYDPI;
};
HRESULT CHiResUnitConvert::Init()
{
HRESULT hr = S_OK;
IHTMLScreen *pScreen = NULL;
IHTMLScreen2 *pScreen2 = NULL;
if (!_pWindow2)
{
hr = E_FAIL;
goto Cleanup;
}
_fInited = TRUE;
hr = _pWindow2->get_screen(&pScreen);
if (!SUCCEEDED(hr))
goto Cleanup;
hr = pScreen->QueryInterface(IID_PPV_ARG(IHTMLScreen2, &pScreen2));
if (!SUCCEEDED(hr))
goto Cleanup;
hr = pScreen2->get_logicalXDPI(&_llogicalXDPI);
if (!SUCCEEDED(hr))
goto Cleanup;
hr = pScreen2->get_logicalYDPI(&_llogicalYDPI);
if (!SUCCEEDED(hr))
goto Cleanup;
hr = pScreen2->get_deviceXDPI(&_ldeviceXDPI);
if (!SUCCEEDED(hr))
goto Cleanup;
hr = pScreen2->get_deviceYDPI(&_ldeviceYDPI);
if (!SUCCEEDED(hr))
goto Cleanup;
#if DBG == 1
{
WCHAR wcBuffer[255];
StringCchPrintf(wcBuffer, ARRAYSIZE(wcBuffer), _T("logical: [%d]-[%d], device: [%d]-[%d]"), _llogicalXDPI, _llogicalYDPI, _ldeviceXDPI, _ldeviceYDPI);
OutputDebugString(wcBuffer);
}
#endif
Cleanup:
if (pScreen)
pScreen->Release();
if (pScreen2)
pScreen2->Release();
return hr;
}
HRESULT CIEFrameAuto::COmWindow::_ParseOptionString(BSTR bstrOptionString, ITargetNotify2 * ptgnNotify2 /* = NULL */)
{
BSTR optionName = NULL;
BSTR optionValue = NULL;
int fValue = TRUE;
BOOL fFirstSet = TRUE;
IHTMLWindow2 *pWindow = NULL;
BOOL fFullScreen = FALSE;
BOOL fChannelMode = FALSE;
if (!SUCCEEDED(_GetWindowDelegate(&pWindow)) && ptgnNotify2)
{
ptgnNotify2->QueryInterface(IID_PPV_ARG(IHTMLWindow2, &pWindow));
}
CHiResUnitConvert unitcvt(pWindow);
// CHiResUnitConvert's constructor AddRefs pWindow, we can release this here
if (pWindow)
pWindow->Release();
// Parse the options
while (GetNextOption(bstrOptionString, &optionName, &fValue))
{
if (fFirstSet)
{
// Netscape's interpretation is, if you set any open options
// then, unless explicitly set, turn off various UI options
_OpenOptions.fToolbar = FALSE;
_OpenOptions.fLocation = FALSE;
_OpenOptions.fDirectories = FALSE;
_OpenOptions.fStatus = FALSE;
_OpenOptions.fMenubar = FALSE;
_OpenOptions.fScrollbars = FALSE;
_OpenOptions.fResizable = FALSE;
fFirstSet = FALSE;
}
if (!StrCmpIW(L"toolbar", optionName))
_OpenOptions.fToolbar = fValue;
else if (!StrCmpIW(L"location", optionName))
_OpenOptions.fLocation = fValue;
else if (!StrCmpIW(L"directories", optionName))
_OpenOptions.fDirectories = fValue;
else if (!StrCmpIW(L"status", optionName))
_OpenOptions.fStatus = fValue;
else if (!StrCmpIW(L"menubar", optionName))
_OpenOptions.fMenubar = fValue;
else if (!StrCmpIW(L"scrollbars", optionName))
_OpenOptions.fScrollbars = fValue;
else if (!StrCmpIW(L"resizable", optionName))
_OpenOptions.fResizable = fValue;
else if (!StrCmpIW(L"width", optionName))
_OpenOptions.iWidth = unitcvt.DeviceFromDocPixelsX(fValue);
else if (!StrCmpIW(L"height", optionName))
_OpenOptions.iHeight = unitcvt.DeviceFromDocPixelsY(fValue);
else if (!StrCmpIW(L"fullscreen", optionName))
fFullScreen = fValue;
else if (!StrCmpIW(L"top", optionName))
_OpenOptions.iTop = unitcvt.DeviceFromDocPixelsY(fValue);
else if (!StrCmpIW(L"left", optionName))
_OpenOptions.iLeft = unitcvt.DeviceFromDocPixelsX(fValue);
else if (!StrCmpIW(L"channelmode", optionName))
fChannelMode = fValue;
else if (!StrCmpIW(L"titlebar", optionName))
_OpenOptions.fTitlebar = fValue;
SysFreeString(optionName);
}
// We no longer allow fullscreen mode. However,
// setting channel and fullscreen does something
// different that we want to keep
if (fFullScreen && fChannelMode)
{
_OpenOptions.fChannelMode = TRUE;
_OpenOptions.fFullScreen = TRUE;
}
else if (fFullScreen || fChannelMode)
{
_OpenOptions.fChannelMode = TRUE;
}
return S_OK;
}
// *** ITargetNotify members ***
/******************************************************************************
Called when navigate must create a new window. pUnkDestination is
IWebBrowserApp object for new frame (also HLinkFrame,ITargetFrame).
******************************************************************************/
HRESULT CIEFrameAuto::COmWindow::OnCreate(IUnknown *pUnkDestination, ULONG cbCookie)
{
if (!pUnkDestination)
{
_fCallbackOK = FALSE;
return E_FAIL;
}
IWebBrowser2 *pNewIE = NULL;
HRESULT hr = pUnkDestination->QueryInterface(IID_PPV_ARG(IWebBrowser2, &pNewIE));
if (SUCCEEDED(hr))
{
_ApplyOpenOptions(pNewIE);
SAFERELEASE(_pOpenedWindow);
// We do not want to release this window. It will be handed out
// to caller of window.open. It is up to the caller to release it.
hr = GetWindowFromUnknown(pUnkDestination, &_pOpenedWindow);
if (SUCCEEDED(hr))
{
VARIANT var, varDummy;
VariantInit(&var);
VariantInit(&varDummy);
var.vt = VT_DISPATCH;
var.pdispVal = static_cast<CAutomationStub*>(this);
// call dummy put_opener in order to make use of its marshalling to set
// child flag in opened window
V_VT(&varDummy) = VT_BOOL;
V_BOOL(&varDummy) = 666;
hr = _pOpenedWindow->put_opener(varDummy);
// set actual opener
hr = _pOpenedWindow->put_opener(var);
}
//bradsch 10/27/96
//Need some code here that tells the IWebBrowserApp not to persist its state.
//This capability does not yet exist on IWebBrowserApp, mikesch is adding it.
pNewIE->Release();
}
if (SUCCEEDED(hr))
_fCallbackOK = TRUE;
return hr;
}
HRESULT CIEFrameAuto::COmWindow::OnReuse(IUnknown *pUnkDestination)
{
if (!pUnkDestination)
{
_fCallbackOK = FALSE;
return E_FAIL;
}
SAFERELEASE(_pOpenedWindow);
// We do not want to release this window. It will be handed out
// to caller of window.open. It is up to the caller to release it.
HRESULT hr = GetWindowFromUnknown(pUnkDestination, &_pOpenedWindow);
if (SUCCEEDED(hr))
_fCallbackOK = TRUE;
return hr;
}
HRESULT CIEFrameAuto::COmWindow::_ApplyOpenOptions(IWebBrowser2 *pie)
{
BOOL fMinusOne = FALSE;
ASSERT(pie);
// test TRUE explictly, as "2" is used as not inited
if (TRUE == _OpenOptions.fChannelMode)
{
pie->put_TheaterMode(-1);
if (!SHRestricted2W(REST_NoChannelUI, NULL, 0))
{
SA_BSTRGUID strGuid;
VARIANT vaGuid;
InitFakeBSTR(&strGuid, CLSID_FavBand);
vaGuid.vt = VT_BSTR;
vaGuid.bstrVal = strGuid.wsz;
pie->ShowBrowserBar(&vaGuid, NULL, NULL);
}
}
else if (_OpenOptions.fLocation
|| _OpenOptions.fDirectories
|| (_OpenOptions.fToolbar && _OpenOptions.fToolbar != CIEFrameAuto::COmWindow::BOOL_NOTSET)
|| _OpenOptions.fMenubar)
{
// If either "location=yes" (Address bar) or "directories=yes" (Quick Links bar) or
// "toolbar=yes" are on, we need the internet toolbar to be on.
// Then we can turn off the bands we don't want.
//
pie->put_ToolBar(TRUE);
// We need to use the ShowBrowserBar method to handle bars/bands for which we don't have individual
// properties.
//
VARIANT varClsid, varShow, varOptional;
VariantInit(&varClsid);
VariantInit(&varShow);
VariantInit(&varOptional);
varClsid.vt = VT_I2;
varShow.vt = VT_BOOL;
varShow.boolVal = VARIANT_FALSE;
varOptional.vt = VT_ERROR;
varOptional.scode = DISP_E_PARAMNOTFOUND;
// "location=yes/no"
//
pie->put_AddressBar(BOOLIFY(_OpenOptions.fLocation));
fMinusOne = fMinusOne || !_OpenOptions.fLocation;
// "toolbar=yes/no"
//
varClsid.iVal = FCW_TOOLBAND;
varShow.boolVal = TO_VARIANT_BOOL(_OpenOptions.fToolbar);
pie->ShowBrowserBar(&varClsid, &varShow, &varOptional);
fMinusOne = fMinusOne || !_OpenOptions.fToolbar;
// "directories=yes/no"
//
varClsid.iVal = FCW_LINKSBAR;
varShow.boolVal = TO_VARIANT_BOOL(_OpenOptions.fDirectories);
pie->ShowBrowserBar(&varClsid, &varShow, &varOptional);
fMinusOne = fMinusOne || !_OpenOptions.fDirectories;
}
else
{
pie->put_ToolBar(FALSE);
}
// "statusbar=yes/no"
//
pie->put_StatusBar(BOOLIFY(_OpenOptions.fStatus));
fMinusOne = fMinusOne || !_OpenOptions.fStatus;
// "menubar=yes/no"
//
pie->put_MenuBar(BOOLIFY(_OpenOptions.fMenubar));
fMinusOne = fMinusOne || !_OpenOptions.fMenubar;
if (CIEFrameAuto::COmWindow::BOOL_NOTSET != _OpenOptions.fFullScreen)
pie->put_FullScreen(_OpenOptions.fFullScreen);
if (_OpenOptions.fScrollbars == FALSE)
{
DWORD dwFlags;
LPTARGETFRAME2 ptgf;
if (SUCCEEDED(pie->QueryInterface(IID_PPV_ARG(ITargetFrame2, &ptgf))))
{
if (SUCCEEDED(ptgf->GetFrameOptions(&dwFlags)))
{
if (_OpenOptions.fScrollbars == FALSE)
{
dwFlags &= ~(FRAMEOPTIONS_SCROLL_YES|FRAMEOPTIONS_SCROLL_NO|FRAMEOPTIONS_SCROLL_AUTO);
dwFlags |= FRAMEOPTIONS_SCROLL_NO;
}
ptgf->SetFrameOptions(dwFlags);
}
ptgf->Release();
}
}
pie->put_Resizable(BOOLIFY(_OpenOptions.fResizable));
// Only use the position and size information if the
// the script does not enable full-screen mode
if (TRUE != _OpenOptions.fFullScreen)
{
CIEFrameAuto * pFrameAuto = SAFECAST(pie, CIEFrameAuto *);
if (pFrameAuto)
pFrameAuto->put_Titlebar(_OpenOptions.fTitlebar);
// If the script specifies no size or positional information and
// the current window is in FullScreen mode then open the new
// window in FullScreen mode as well.
if (_OpenOptions.iWidth < 0 && _OpenOptions.iHeight < 0 && _OpenOptions.iTop < 0 && _OpenOptions.iLeft < 0)
{
VARIANT_BOOL fs = 0;
CIEFrameAuto* pauto = IToClass(CIEFrameAuto, _omwin, this);
HRESULT hr = pauto->get_FullScreen(&fs);
if (SUCCEEDED(hr) && fs)
pie->put_FullScreen(fs);
}
else
{
int iWidth = _OpenOptions.iWidth > 0 ? _OpenOptions.iWidth:300;
int iHeight = _OpenOptions.iHeight > 0 ? _OpenOptions.iHeight:300;
// Set a minimum size of 100x100
iWidth = iWidth > 100 ? iWidth : 100;
iHeight = iHeight > 100 ? iHeight : 100;
// Yes! Netscape doesn't treat the width and height as a content
// size when at least one adornment is turned off
if (fMinusOne) pie->ClientToWindow(&iWidth, &iHeight);
if (_OpenOptions.iWidth > 0)
pie->put_Width(iWidth);
if (_OpenOptions.iHeight > 0)
pie->put_Height(iHeight);
if (_OpenOptions.iTop >= 0)
pie->put_Top(_OpenOptions.iTop);
if (_OpenOptions.iLeft >= 0)
pie->put_Left(_OpenOptions.iLeft);
}
}
return S_OK;
}
HRESULT CIEFrameAuto::COmWindow::get_document(IHTMLDocument2 **ppomDocumentResult)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_document(ppomDocumentResult);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::navigate(BSTR url)
{
// This will do all the fun things that must be done
// to an URL before is can be used to navigate.
return _pAuto->_omloc.put_href(url);
}
/******************************************************************************
get_opener -
Returns the value of the opener property.
******************************************************************************/
HRESULT CIEFrameAuto::COmWindow::get_opener(
/* [retval][out] */ VARIANT *pretval)
{
if (!pretval)
return E_POINTER;
return VariantCopy(pretval, &_varOpener);
}
/******************************************************************************
put_opener -
Sets the opener property opener of this window. This method may
be called either internally (from C++ code) or from a script. We must
Release our current opener if the new opener is valid (or VT_NULL).
COmWindow's DeInit method ensures this never causes a circular reference
when this object is in the same thread as "opener".
******************************************************************************/
HRESULT CIEFrameAuto::COmWindow::put_opener(VARIANT opener)
{
// piggy back on put_opener's marshalling to set child flag. This will be called
// with VT_TYPE==VT_BOOL and a value of 666 only from oncreate(). Chances of this
// happening from script is very remote.
if (!_fIsChild && V_VT(&opener) == VT_BOOL && V_BOOL(&opener) == 666)
{
_fIsChild = TRUE;
return S_OK;
}
return VariantCopy(&_varOpener, &opener);
}
/******************************************************************************
executScript -
immediately executes the script passed in. needed for the multimedia
controls
******************************************************************************/
HRESULT CIEFrameAuto::COmWindow::execScript(
/* [in] */ BSTR bstrCode,
/* [in] */ BSTR bstrLanguage,
/* [out] */ VARIANT *pvarRet)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->execScript(bstrCode, bstrLanguage, pvarRet);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_onblur(VARIANT *p)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_onblur(p);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::put_onblur(
/* [in] */ VARIANT v)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_onblur(v);
pWindow->Release();
}
return hr;
}
/******************************************************************************
get_onfocus -
Returns the value of the onfocus property.
******************************************************************************/
HRESULT CIEFrameAuto::COmWindow::get_onfocus(VARIANT *p)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_onfocus(p);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::put_onfocus(
/* [in] */ VARIANT v)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_onfocus(v);
pWindow->Release();
}
return hr;
}
/******************************************************************************
get_onload -
Returns the value of the onload property.
******************************************************************************/
HRESULT CIEFrameAuto::COmWindow::get_onload(
/* [p][out] */ VARIANT *p)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_onload(p);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::put_onload(VARIANT v)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_onload(v);
pWindow->Release();
}
return hr;
}
/******************************************************************************
get_onunload -
Returns the value of the onunload property.
******************************************************************************/
HRESULT CIEFrameAuto::COmWindow::get_onunload(
/* [p][out] */ VARIANT *p)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_onunload(p);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::put_onunload(VARIANT v)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_onunload(v);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::put_onbeforeunload(VARIANT v)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_onbeforeunload(v);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_onbeforeunload(VARIANT *p)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_onbeforeunload(p);
pWindow->Release();
}
return hr;
}
/******************************************************************************
get_onhelp -
Returns the value of the onhelp property.
******************************************************************************/
HRESULT CIEFrameAuto::COmWindow::get_onhelp(
/* [p][out] */ VARIANT *p)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_onhelp(p);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::put_onhelp(VARIANT v)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_onhelp(v);
pWindow->Release();
}
return hr;
}
/******************************************************************************
get_onresize -
Returns the value of the resize property.
******************************************************************************/
HRESULT CIEFrameAuto::COmWindow::get_onresize(
/* [p][out] */ VARIANT *p)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_onresize(p);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::put_onresize(VARIANT v)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_onresize(v);
pWindow->Release();
}
return hr;
}
/******************************************************************************
get_onscroll -
Returns the value of the onscroll property.
******************************************************************************/
HRESULT CIEFrameAuto::COmWindow::get_onscroll(
/* [p][out] */ VARIANT *p)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_onscroll(p);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::put_onscroll(VARIANT v)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_onscroll(v);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_Image(IHTMLImageElementFactory **retval)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_Image(retval);
pWindow->Release();
}
return hr;
}
/******************************************************************************
get_onerror -
Returns the value of the onerror property.
******************************************************************************/
HRESULT CIEFrameAuto::COmWindow::get_onerror(
/* [p][out] */ VARIANT *p)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_onerror(p);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::put_onerror(VARIANT v)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_onerror(v);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_event(IHTMLEventObj **p)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_event(p);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get__newEnum(IUnknown **p)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get__newEnum(p);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::showModalDialog(BSTR dialog,
VARIANT* varArgIn,
VARIANT* varOptions,
VARIANT* varArgOut)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->showModalDialog(dialog, varArgIn, varOptions, varArgOut);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::showHelp(BSTR helpURL, VARIANT helpArg, BSTR features)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->showHelp(helpURL, helpArg, features);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_screen(IHTMLScreen **p)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_screen(p);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_Option(IHTMLOptionElementFactory **retval)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_Option(retval);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::toString(BSTR *Str)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->toString(Str);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::scrollBy(long x, long y)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->scrollBy(x, y);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::scrollTo(long x, long y)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->scrollTo(x, y);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_external(IDispatch **ppDisp)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_external(ppDisp);
pWindow->Release();
}
return hr;
}
// **** IHTMLWindow3 ****
HRESULT CIEFrameAuto::COmWindow::print()
{
IHTMLWindow3 *pWindow = NULL;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->print();
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::showModelessDialog(BSTR strUrl,
VARIANT * pvarArgIn,
VARIANT * pvarOptions,
IHTMLWindow2 ** ppDialog)
{
IHTMLWindow3 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->showModelessDialog(strUrl,
pvarArgIn,
pvarOptions,
ppDialog);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::put_onbeforeprint(VARIANT v)
{
IHTMLWindow3 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_onbeforeprint(v);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_onbeforeprint(VARIANT *p)
{
IHTMLWindow3 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_onbeforeprint(p);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::put_onafterprint(VARIANT v)
{
IHTMLWindow3 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_onafterprint(v);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_onafterprint(VARIANT *p)
{
IHTMLWindow3 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_onafterprint(p);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_screenTop(long *plVal)
{
IHTMLWindow3 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_screenTop(plVal);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_screenLeft(long *plVal)
{
IHTMLWindow3 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_screenLeft(plVal);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_clipboardData(IHTMLDataTransfer **ppDataTransfer)
{
IHTMLWindow3 *pWindow = NULL;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_clipboardData(ppDataTransfer);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::attachEvent(BSTR event, IDispatch* pDisp, VARIANT_BOOL *pResult)
{
IHTMLWindow3 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->attachEvent(event, pDisp, pResult);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::detachEvent(BSTR event, IDispatch* pDisp)
{
IHTMLWindow3 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->detachEvent(event, pDisp);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::setTimeout(
/* [in] */ VARIANT *pExpression,
/* [in] */ long msec,
/* [optional] */ VARIANT *language,
/* [retval][out] */ long *timerID)
{
IHTMLWindow3 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->setTimeout(pExpression, msec, language, timerID);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::setInterval(
/* [in] */ VARIANT *pExpression,
/* [in] */ long msec,
/* [optional] */ VARIANT *language,
/* [retval][out] */ long *timerID)
{
IHTMLWindow3 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->setInterval(pExpression, msec, language, timerID);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::moveTo(long x, long y)
{
HWND hwnd = _pAuto->_GetHWND();
if (!hwnd)
return S_OK;
::SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE);
return S_OK;
}
HRESULT CIEFrameAuto::COmWindow::moveBy(long x, long y)
{
HWND hwnd = _pAuto->_GetHWND();
RECT rcWindow;
if (!hwnd)
return S_OK;
::GetWindowRect (hwnd, &rcWindow);
::SetWindowPos(hwnd, NULL, rcWindow.left+x, rcWindow.top+y, 0, 0, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE);
return S_OK;
}
HRESULT CIEFrameAuto::COmWindow::resizeTo(long x, long y)
{
HWND hwnd = _pAuto->_GetHWND();
if (!hwnd)
return S_OK;
if (x < 100)
x = 100;
if (y < 100)
y = 100;
::SetWindowPos(hwnd, NULL, 0, 0, x, y, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE);
return S_OK;
}
HRESULT CIEFrameAuto::COmWindow::resizeBy(long x, long y)
{
HWND hwnd = _pAuto->_GetHWND();
RECT rcWindow;
long w, h;
if (!hwnd)
return S_OK;
::GetWindowRect (hwnd, &rcWindow);
w = rcWindow.right - rcWindow.left + x;
h = rcWindow.bottom - rcWindow.top + y;
if (w < 100)
w = 100;
if (h < 100)
h = 100;
::SetWindowPos(hwnd, NULL, 0, 0, w, h, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE);
return S_OK;
}
HRESULT CIEFrameAuto::COmWindow::_GetWindowDelegate(IHTMLWindow2 **ppomwDelegate)
{
if (!ppomwDelegate)
return E_POINTER;
IDispatch *pRootDisp = 0;
HRESULT hr = GetRootDelegate(_pAuto, &pRootDisp);
if (SUCCEEDED(hr))
{
hr = pRootDisp->QueryInterface(IID_PPV_ARG(IHTMLWindow2, ppomwDelegate));
pRootDisp->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::_GetWindowDelegate(IHTMLWindow3 **ppomwDelegate)
{
if (!ppomwDelegate)
return E_POINTER;
IDispatch *pRootDisp = 0;
HRESULT hr = GetRootDelegate(_pAuto, &pRootDisp);
if (SUCCEEDED(hr))
{
hr = pRootDisp->QueryInterface(IID_PPV_ARG(IHTMLWindow3, ppomwDelegate));
pRootDisp->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::SinkDelegate()
{
// Force an Unadvise if we already have a connection
if (_pCP)
UnsinkDelegate();
// If we do not have anyone sinking us, then we don't need to sink our
// delegate. If someone sinks us later we will sink our delegate in
// the IConnectionPointCB::OnAdvise callback.
if (_cpWindowEvents.IsEmpty())
return S_OK;
IHTMLWindow2 *pWindow;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
// We have to connect to the event source to get Trident specific events.
hr = ConnectToConnectionPoint(&_wesDelegate, DIID_HTMLWindowEvents, TRUE, pWindow, &_dwCPCookie, &_pCP);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::UnsinkDelegate()
{
if (_pCP)
{
_pCP->Unadvise(_dwCPCookie);
_pCP->Release();
_pCP = 0;
_dwCPCookie = 0;
}
return S_OK;
}
/******************************************************************************
Someone has sinked our events. This means we need to sink the events of our
delegate docobject if we have not already done so.
******************************************************************************/
HRESULT CIEFrameAuto::COmWindow::OnAdvise(REFIID iid, DWORD cSinks, ULONG_PTR dwCookie)
{
HRESULT hr;
if (!_pCP)
hr = SinkDelegate();
else
hr = S_OK;
return hr;
}
HRESULT CIEFrameAuto::COmWindow::FireOnUnload()
{
HRESULT hr;
if (_fOnloadFired)
{
hr = _cpWindowEvents.InvokeDispid(DISPID_ONUNLOAD);
_fOnloadFired = FALSE;
}
else
hr = S_OK;
return hr;
}
HRESULT CIEFrameAuto::COmWindow::FireOnLoad()
{
HRESULT hr;
if (!_fOnloadFired)
{
hr = _cpWindowEvents.InvokeDispid(DISPID_ONUNLOAD);
_fOnloadFired = TRUE;
}
else
hr = S_OK;
return hr;
}
/******************************************************************************
Check of the docobject document is complete. The document is considered
complete if either:
- The document has reached READYSTATE_COMPLETE or
- The document does not support the DISPID_READYSTATE property
If the document is not complete, the caller of this method knows the
delegate supports the READYSTATE property and will receive a future
READYSTATE_COMPLETE notification.
******************************************************************************/
BOOL CIEFrameAuto::COmWindow::IsDelegateComplete()
{
ASSERT(_pAuto);
BOOL fSupportsReadystate = FALSE;
BOOL fComplete = FALSE;
// Check for proper readystate support
IDispatch *pdispatch;
if (SUCCEEDED(_pAuto->get_Document(&pdispatch)))
{
VARIANTARG va;
EXCEPINFO excp;
if (SUCCEEDED(pdispatch->Invoke(DISPID_READYSTATE,
IID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYGET,
(DISPPARAMS *)&g_dispparamsNoArgs,
&va,
&excp,
NULL)))
{
fSupportsReadystate = TRUE;
if (VT_I4 == va.vt && READYSTATE_COMPLETE == va.lVal)
fComplete = TRUE;
}
pdispatch->Release();
}
return !fSupportsReadystate || fComplete;
}
STDMETHODIMP CIEFrameAuto::COmWindow::CWindowEventSink::QueryInterface(REFIID riid, void **ppv)
{
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_IDispatch) ||
IsEqualIID(riid, DIID_HTMLWindowEvents) )
{
*ppv = SAFECAST(this, IDispatch*);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
/******************************************************************************
We want to bind the lifetime of our owning object to this object
******************************************************************************/
ULONG CIEFrameAuto::COmWindow::CWindowEventSink::AddRef(void)
{
COmWindow* pwin = IToClass(COmWindow, _wesDelegate, this);
return pwin->AddRef();
}
/******************************************************************************
We want to bind the lifetime of our owning object to this object
******************************************************************************/
ULONG CIEFrameAuto::COmWindow::CWindowEventSink::Release(void)
{
COmWindow* pwin = IToClass(COmWindow, _wesDelegate, this);
return pwin->Release();
}
// *** IDispatch ***
STDMETHODIMP CIEFrameAuto::COmWindow::CWindowEventSink::Invoke(
DISPID dispid,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS *pdispparams,
VARIANT *pvarResult,
EXCEPINFO *pexcepinfo,
UINT *puArgErr )
{
HRESULT hr;
// This object just acts as a pass through for our delegate's
// window object. Since we interally generated events for both
// DISPID_ONLOAD
// DISPID_ONUNLOAD
// we just ignore those that are sourced by our delegate.
if (DISPID_ONLOAD == dispid ||
DISPID_ONUNLOAD == dispid )
{
hr = S_OK;
}
else
{
COmWindow* pwin = IToClass(COmWindow, _wesDelegate, this);
hr = pwin->_cpWindowEvents.InvokeDispid(dispid);
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::put_offscreenBuffering(VARIANT var)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->put_offscreenBuffering(var);
pWindow->Release();
}
return hr;
}
HRESULT CIEFrameAuto::COmWindow::get_offscreenBuffering(VARIANT *retval)
{
IHTMLWindow2 *pWindow = 0;
HRESULT hr = _GetWindowDelegate(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_offscreenBuffering(retval);
pWindow->Release();
}
return hr;
}
// *** IConnectionPointContainer ***
STDMETHODIMP CIEFrameAuto::COmWindow::FindConnectionPoint(REFIID iid, LPCONNECTIONPOINT *ppCP)
{
ASSERT(ppCP);
if (!ppCP)
return E_POINTER;
if (IsEqualIID(iid, DIID_HTMLWindowEvents) || IsEqualIID(iid, IID_IDispatch))
{
*ppCP = _cpWindowEvents.CastToIConnectionPoint();
}
else
{
*ppCP = NULL;
return E_NOINTERFACE;
}
(*ppCP)->AddRef();
return S_OK;
}
STDMETHODIMP CIEFrameAuto::COmWindow::EnumConnectionPoints(LPENUMCONNECTIONPOINTS * ppEnum)
{
return CreateInstance_IEnumConnectionPoints(ppEnum, 1,
_cpWindowEvents.CastToIConnectionPoint());
}
/******************************************************************************
Location Object
// bradsch 11/12/96
// The entire COmLocation object was copied from MSHTML and is a slimy pig
// dog. It should be replaced with the new URL cracking stuff in SHLWAPI.
******************************************************************************/
CIEFrameAuto::COmLocation::COmLocation() :
CAutomationStub(MIN_BROWSER_DISPID, MAX_BROWSER_DISPID, TRUE)
{
ASSERT(!m_bstrFullUrl);
ASSERT(!m_bstrPort);
ASSERT(!m_bstrProtocol);
ASSERT(!m_bstrHostName);
ASSERT(!m_bstrPath);
ASSERT(!m_bstrSearch);
ASSERT(!m_bstrHash);
ASSERT(FALSE == m_fdontputinhistory);
ASSERT(FALSE == m_fRetryingNavigate);
}
HRESULT CIEFrameAuto::COmLocation::Init()
{
CIEFrameAuto* pauto = IToClass(CIEFrameAuto, _omloc, this);
return CAutomationStub::Init(SAFECAST(this, IHTMLLocation*), IID_IHTMLLocation, CLSID_HTMLLocation, pauto);
}
HRESULT CIEFrameAuto::COmLocation::CheckUrl()
{
BSTR currentUrl = 0;
HRESULT hr;
VARIANT varUrl;
VariantInit(&varUrl);
hr = _pAuto->_QueryPendingUrl(&varUrl);
if (FAILED(hr) || varUrl.vt != VT_BSTR || varUrl.bstrVal == NULL)
{
VariantClearLazy(&varUrl);
hr = _pAuto->get_LocationURL(&currentUrl);
}
else
{
// No VariantClear, we're extracting the bstrVal
currentUrl = varUrl.bstrVal;
}
if (SUCCEEDED(hr))
{
// If our stashed URL does not match the real current URL we need to reparse everything
if (!m_bstrFullUrl || StrCmpW(m_bstrFullUrl, currentUrl))
{
// This code is all going to change, so I am not worried about efficiency
FreeStuff();
m_bstrFullUrl = currentUrl;
hr = ParseUrl();
}
else
SysFreeString(currentUrl);
}
return hr;
}
HRESULT CIEFrameAuto::COmLocation::_InternalQueryInterface(REFIID riid, void ** const ppv)
{
ASSERT(!IsEqualIID(riid, IID_IUnknown));
if (IsEqualIID(riid, IID_IHTMLLocation))
*ppv = SAFECAST(this, IHTMLLocation *);
else if (IsEqualIID(riid, IID_IServiceProvider))
*ppv = SAFECAST(this, IObjectIdentity *);
else if (IsEqualIID(riid, IID_IObjectIdentity))
*ppv = SAFECAST(this, IServiceProvider *);
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
HRESULT CIEFrameAuto::COmLocation::_GetIDispatchExDelegate(IDispatchEx ** const delegate)
{
if (!delegate)
return E_POINTER;
IDispatch *pRootDisp = 0;
HRESULT hr = GetRootDelegate(_pAuto, &pRootDisp);
if (SUCCEEDED(hr))
{
IDispatch *pDelegateDisp = 0;
hr = GetDelegateOnIDispatch(pRootDisp, DISPID_LOCATIONOBJECT, &pDelegateDisp);
pRootDisp->Release();
if (SUCCEEDED(hr))
{
hr = pDelegateDisp->QueryInterface(IID_IDispatchEx, (void**)delegate);
pDelegateDisp->Release();
}
}
return hr;
}
/****************************************************************************
IObjectIdentity member implemtnation. this is necessary since mshtml has a locatino
proxy that it returns, whichc is a different pUnk than the location object returned by
shdocvw. The script engines use this interface to resolve the difference and allow
equality test to be perfomed on these objects.
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmLocation::IsEqualObject(IUnknown * pUnk)
{
HRESULT hr;
IServiceProvider * pISP = NULL;
IHTMLLocation * pLoc = NULL;
IUnknown * pUnkThis = NULL;
IUnknown * pUnkTarget = NULL;
if (!pUnk)
return E_POINTER;
hr = pUnk->QueryInterface(IID_IServiceProvider, (void**)&pISP);
if (!SUCCEEDED(hr))
goto Cleanup;
hr = pISP->QueryService(IID_IHTMLLocation, IID_IHTMLLocation, (void**)&pLoc);
if (!SUCCEEDED(hr))
goto Cleanup;
hr = pLoc->QueryInterface(IID_IUnknown, (void**)&pUnkTarget);
if (!SUCCEEDED(hr))
goto Cleanup;
hr = QueryInterface(IID_IUnknown, (void**)&pUnkThis);
if (!SUCCEEDED(hr))
goto Cleanup;
hr = (pUnkThis == pUnkTarget) ? S_OK : S_FALSE;
Cleanup:
if (pISP) ATOMICRELEASE(pISP);
if (pLoc) ATOMICRELEASE(pLoc);
if (pUnkTarget) ATOMICRELEASE(pUnkTarget);
if (pUnkThis) ATOMICRELEASE(pUnkThis);
return hr;
}
/*****************************************************************************
IServiceProvider - this is currently only used by the impl of ISEqual object
on mshtml side,. adn only needs to return *this* when Queryied for location
service
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmLocation::QueryService(REFGUID guidService, REFIID iid, void ** ppv)
{
HRESULT hr = E_NOINTERFACE;
if (!ppv)
return E_POINTER;
*ppv = NULL;
if (IsEqualGUID(guidService, IID_IHTMLLocation))
{
*ppv = SAFECAST(this, IHTMLLocation *);
hr = S_OK;
}
return hr;
}
/******************************************************************************
Helper function for the property access functions
Makes sure that the URL has been parsed and returns a copy
of the requested field as a BSTR.
******************************************************************************/
HRESULT CIEFrameAuto::COmLocation::GetField(BSTR* bstrField, BSTR* pbstr)
{
HRESULT hr;
if (!pbstr)
return E_INVALIDARG;
if (!bstrField)
return E_FAIL;
hr = CheckUrl();
if (FAILED(hr))
return hr;
*pbstr = *bstrField ? SysAllocString(*bstrField): SysAllocString(L"");
return (*pbstr) ? S_OK : E_OUTOFMEMORY;
}
STDMETHODIMP CIEFrameAuto::COmLocation::toString (BSTR* pbstr)
{
return GetField(&m_bstrFullUrl, pbstr);
}
STDMETHODIMP CIEFrameAuto::COmLocation::get_href(BSTR* pbstr)
{
return GetField(&m_bstrFullUrl, pbstr);
}
STDMETHODIMP CIEFrameAuto::COmLocation::get_protocol(BSTR* pbstr)
{
return GetField(&m_bstrProtocol, pbstr);
}
STDMETHODIMP CIEFrameAuto::COmLocation::get_hostname(BSTR* pbstr)
{
return GetField(&m_bstrHostName, pbstr);
}
STDMETHODIMP CIEFrameAuto::COmLocation::get_host(BSTR* pbstr)
{
HRESULT hr;
INT cch;
BOOL fHavePort;
hr = CheckUrl();
if (FAILED(hr))
return hr;
if (!m_bstrHostName)
return E_POINTER;
cch = lstrlenW(m_bstrHostName);
fHavePort = m_bstrPort && *m_bstrPort;
if (fHavePort)
cch += lstrlenW(m_bstrPort) + 1; // for the ":"
*pbstr = SafeSysAllocStringLen(0, cch); // allocates cch + 1
if (!*pbstr)
return E_OUTOFMEMORY;
// Get the hostname
StrCpyNW(*pbstr, m_bstrHostName, cch + 1);
// add additional character for colon
// concatenate ":" and the port number, if there is a port number
if (fHavePort)
{
StrCatBuffW(*pbstr, L":", cch + 1);
StrCatBuffW(*pbstr, m_bstrPort, cch + 1);
}
return S_OK;
}
STDMETHODIMP CIEFrameAuto::COmLocation::get_pathname(BSTR* pbstr)
{
// Hack for Netscape compatability -- not in Nav3 or nav4.maybe in nav2?
// Netscape returned nothing for a path of "/"
// we used to do this but it looks like we should follow nav3/4 now (for OMCOMPAT)
return GetField(&m_bstrPath, pbstr);
}
STDMETHODIMP CIEFrameAuto::COmLocation::get_search(BSTR* pbstr)
{
return GetField(&m_bstrSearch, pbstr);
}
STDMETHODIMP CIEFrameAuto::COmLocation::get_hash(BSTR* pbstr)
{
return GetField(&m_bstrHash, pbstr);
}
STDMETHODIMP CIEFrameAuto::COmLocation::get_port(BSTR* pbstr)
{
return GetField(&m_bstrPort, pbstr);
}
STDMETHODIMP CIEFrameAuto::COmLocation::reload(VARIANT_BOOL fFlag)
{
VARIANT v = {0};
v.vt = VT_I4;
v.lVal = fFlag ?
OLECMDIDF_REFRESH_COMPLETELY|OLECMDIDF_REFRESH_CLEARUSERINPUT :
OLECMDIDF_REFRESH_NO_CACHE|OLECMDIDF_REFRESH_CLEARUSERINPUT;
return _pAuto->Refresh2(&v);
}
STDMETHODIMP CIEFrameAuto::COmLocation::replace(BSTR url)
{
m_fdontputinhistory = TRUE;
return put_href(url);
}
STDMETHODIMP CIEFrameAuto::COmLocation::assign(BSTR url)
{
return put_href(url);
}
void CIEFrameAuto::COmLocation::RetryNavigate()
{
//
// If a page does a navigate on an unload event and the unload is happening
// because the user shutdown the browser we would recurse to death.
// m_fRetryingNavigate was added to fix this scenario.
//
if (m_fPendingNavigate && !m_fRetryingNavigate)
{
m_fRetryingNavigate = TRUE;
DoNavigate();
m_fRetryingNavigate = FALSE;
}
}
//
//
// PrvHTParse - wrapper for Internet{Canonicalize/Combine}Url
// which does a local allocation of our returned string so we can
// free it as needed.
//
//
// We start by calling InternetCanonicalizeUrl() to perform any required
// canonicalization. If the caller specificed PARSE_ALL, we're done at that
// point and return the URL. This is the most common case.
//
// If the caller wanted parts of the URL, we will then call
// InternetCrackUrl() to break the URL into it's components, and
// finally InternetCreateUrl() to give us a string with just those
// components.
//
// ICU() has a bug which forces it to always prepend a scheme, so we have
// some final code at the end which removes the scheme if the caller
// specifically did not want one.
//
#define STARTING_URL_SIZE 127 // 128 minus 1
#define PARSE_ACCESS 16
#define PARSE_HOST 8
#define PARSE_PATH 4
#define PARSE_ANCHOR 2
#define PARSE_PUNCTUATION 1
#define PARSE_ALL 31
BSTR PrvHTParse(BSTR bstraName, BSTR bstrBaseName, int wanted)
{
DWORD cchP = STARTING_URL_SIZE+1;
DWORD cchNeed = cchP;
BOOL rc;
HRESULT hr;
if ((!bstraName && !bstrBaseName))
return NULL;
WCHAR *p = new WCHAR[cchP];
if (!p)
return NULL;
// ICU() does not accept NULL pointers, but it does handle "" strings
if (!bstrBaseName)
bstrBaseName = L"";
if (!bstraName)
bstraName = L"";
URL_COMPONENTSW uc = {0};
uc.dwStructSize = sizeof(uc);
// We will retry once if the failure was due to an insufficiently large buffer
hr = UrlCombineW(bstrBaseName, bstraName, p, &cchNeed, 0);
if (hr == E_POINTER)
{
// From the code, cchNeed has the same value as if UrlCombine had succeeded,
// which is the length of the combined URL, excluding the null.
cchP = ++cchNeed;
delete [] p;
p = new WCHAR[cchP];
if (!p)
goto free_and_exit;
hr = UrlCombineW(bstrBaseName, bstraName, p, &cchNeed, 0);
}
if (SUCCEEDED(hr) && wanted != PARSE_ALL)
{
// Since CreateUrl() will ignore our request to not add a scheme,
// we always ask it to crack one, so we can know the size if we need
// to remove it ourselves
uc.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH;
uc.lpszScheme = new WCHAR[uc.dwSchemeLength];
if (wanted & PARSE_HOST) {
uc.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
uc.lpszHostName = new WCHAR[uc.dwHostNameLength];
}
if (wanted & PARSE_PATH) {
uc.dwUrlPathLength = INTERNET_MAX_URL_LENGTH;
uc.lpszUrlPath = new WCHAR[uc.dwUrlPathLength];
}
if (wanted & PARSE_ANCHOR) {
uc.dwExtraInfoLength = INTERNET_MAX_URL_LENGTH;
uc.lpszExtraInfo = new WCHAR[uc.dwExtraInfoLength];
}
// if any of our allocations fail, fail the whole operation.
if ((!uc.lpszScheme) ||
((wanted & PARSE_HOST) && (!uc.lpszHostName)) ||
((wanted & PARSE_PATH) && (!uc.lpszUrlPath)) ||
((wanted & PARSE_ANCHOR) && (!uc.lpszExtraInfo)))
goto free_and_exit;
rc = InternetCrackUrlW(p, cchNeed, 0, &uc);
// If we are failing here, we need to figure out why and fix it
if (!rc)
{
//TraceMsg(TF_WARNING, TEXT("PrvHTParse: InternetCrackUrl failed for \"\""), Dbg_SafeStr(p));
goto free_and_exit; // Couldn't crack it, so give back what we can
}
// InternetCreateUrlW takes in a count of WCHARs but if it
// fails, the same variable is set to a count of bytes. So we'll
// call this variable the ambiguous dwLength. Yuck.
cchNeed = cchP;
DWORD dwLength = cchNeed;
rc = InternetCreateUrlW(&uc, 0, p, &dwLength);
if (!rc)
{
delete [] p;
p = NULL;
const DWORD err = GetLastError();
if ((ERROR_INSUFFICIENT_BUFFER == err) && (dwLength > 0))
{
// dwLength comes out in bytes. We'll turn it into a char count
// The previous ANSI version allocated one char too many
// but it's too risky to correct that now
dwLength /= sizeof(WCHAR);
cchP = ++dwLength;
p = new WCHAR[cchP];
if (!p)
goto free_and_exit;
rc = InternetCreateUrlW(&uc, 0, p, &dwLength);
}
} // if !rc
if (rc)
{
// The most recent InternetCreateUrl was successful, so dwLength contains
// the number of wide chars stored in p.
cchNeed = dwLength;
// Special case: remove protocol if not requested. ICU() adds
// a protocol even if you tell it not to.
if (!(wanted & PARSE_ACCESS))
{
WCHAR *q;
// Make sure our string is sufficiently large for
ASSERT(cchNeed > uc.dwSchemeLength);
// For non-pluggable protocols, Add 3 for the ://, which is not counted in the scheme length, else add 1
int cch = lstrlenW(p + uc.dwSchemeLength + ((uc.nScheme == INTERNET_SCHEME_UNKNOWN) ? 1 : 3)) + 1;
q = new WCHAR[cch];
if (q)
{
StrCpyNW(q, (p + uc.dwSchemeLength + ((uc.nScheme == INTERNET_SCHEME_UNKNOWN) ? 1 : 3)), cch);
delete [] p;
p = q;
}
}
else
{
if ((wanted & (~PARSE_PUNCTUATION)) == PARSE_ACCESS)
{
// Special case #2: When only PARSE_ACCESS is requested,
// don't return the // suffix
p[uc.dwSchemeLength + 1] = '\0';
}
}
}
} // if wanted
free_and_exit:
delete [] uc.lpszScheme;
delete [] uc.lpszHostName;
delete [] uc.lpszUrlPath;
delete [] uc.lpszExtraInfo;
BSTR bstrp = 0;
if (p)
{
bstrp = SysAllocString(p);
delete [] p;
}
return bstrp;
}
STDMETHODIMP CIEFrameAuto::COmLocation::put_href(BSTR url)
{
HRESULT hr;
if (!url)
return E_INVALIDARG;
// Call CheckUrl before PrvHTParse to ensure we have a valid URL
hr = CheckUrl();
if (FAILED(hr))
return hr;
BSTR bstrUrlAbsolute = PrvHTParse(url, m_bstrFullUrl, PARSE_ALL);
if (!bstrUrlAbsolute )
return E_OUTOFMEMORY;
// Actually set the URL field
hr = SetField(&m_bstrFullUrl, bstrUrlAbsolute, FALSE);
SysFreeString(bstrUrlAbsolute);
return hr;
}
STDMETHODIMP CIEFrameAuto::COmLocation::put_protocol(BSTR bstr)
{
return SetField(&m_bstrProtocol, bstr, TRUE);
}
STDMETHODIMP CIEFrameAuto::COmLocation::put_hostname(BSTR bstr)
{
return SetField(&m_bstrHostName, bstr, TRUE);
}
STDMETHODIMP CIEFrameAuto::COmLocation::put_host(BSTR bstr)
{
HRESULT hr = S_OK;
WCHAR* colonPos = 0;
WCHAR* portName = NULL;
WCHAR* hostName = NULL;
hr = CheckUrl();
if (FAILED(hr))
return hr;
// Parse out the hostname and port and store them in
// the appropriate fields
colonPos = StrChrW(bstr, L':');
// Copy the characters up to the colon in the
// hostname field
if (colonPos == 0)
{
hostName = SysAllocString(bstr);
portName = SysAllocString(L"");
}
else
{
hostName = SafeSysAllocStringLen(bstr, (unsigned int)(colonPos-bstr));
portName = SafeSysAllocStringLen(colonPos+1, SysStringLen(bstr) - (unsigned int)(colonPos-bstr+1));
}
if (hostName && portName)
{
if (m_bstrHostName)
SysFreeString(m_bstrHostName);
if (m_bstrPort)
SysFreeString(m_bstrPort);
m_bstrHostName = hostName;
m_bstrPort = portName;
hostName = portName = 0;
hr = ComposeUrl();
if (SUCCEEDED(hr))
{
hr = DoNavigate();
}
}
else
hr = E_OUTOFMEMORY;
if (hostName)
SysFreeString(hostName);
if (portName)
SysFreeString(portName);
return hr;
}
STDMETHODIMP CIEFrameAuto::COmLocation::put_pathname(BSTR bstr)
{
return SetField(&m_bstrPath, bstr, TRUE);
}
STDMETHODIMP CIEFrameAuto::COmLocation::put_search(BSTR bstr)
{
if (!bstr)
return E_POINTER;
// If the provided search string begins with a "?" already,
// just use it "as is"
if (bstr[0] == L'?')
{
return SetField(&m_bstrSearch, bstr, TRUE);
}
// Otherwise prepend a question mark
else
{
// Allocate enough space for the string plus one more character ('#')
UINT cchSearch = lstrlenW(bstr) + 1;
BSTR bstrSearch = SafeSysAllocStringLen(L"?", cchSearch); // allocates cch + 1
if (!bstrSearch)
return E_OUTOFMEMORY;
StrCatBuffW(bstrSearch, bstr, cchSearch + 1);
HRESULT hr = SetField(&m_bstrSearch, bstrSearch, TRUE);
SysFreeString(bstrSearch);
return hr;
}
}
STDMETHODIMP CIEFrameAuto::COmLocation::put_hash(BSTR bstr)
{
if (!bstr)
return E_POINTER;
// If the provided hash string begins with a "#" already,
// just use it "as is"
if (bstr[0] == L'#')
{
return SetField(&m_bstrHash, bstr, TRUE);
}
// Otherwise prepend a pound sign
else
{
// Allocate enough space for the string plus one more character ('#')
UINT cchHash = lstrlenW(bstr) + 1;
BSTR bstrHash = SafeSysAllocStringLen(L"#", cchHash); // allocates cchHash + 1
if (!bstrHash)
return E_OUTOFMEMORY;
StrCatBuffW(bstrHash, bstr, cchHash + 1);
HRESULT hr = SetField(&m_bstrHash, bstrHash, TRUE);
SysFreeString(bstrHash);
return hr;
}
}
STDMETHODIMP CIEFrameAuto::COmLocation::put_port(BSTR bstr)
{
return SetField(&m_bstrPort, bstr, TRUE);
}
/******************************************************************************
// Helper function for the property setting functions
// Makes sure that the URL has been parsed
// Sets the field to its new value
// recomposes the URL, IF fRecomposeUrl is true
// If part of a window, tells the window to go to the new URL
//
// @todo JavaScript has some funky behavior on field setting--
// for example, the protocol field can be set to an entire URL.
// We need to make sure this functionality is duplicated
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmLocation::SetField(BSTR* field, BSTR newval, BOOL fRecomposeUrl)
{
HRESULT hr = S_OK;
hr = CheckUrl();
if (FAILED(hr))
return hr;
// Copy the current URL!
BSTR bstrCurrentURL = SysAllocString(m_bstrFullUrl);
// Make a copy of the new value
BSTR valCopy = SysAllocString(newval);
if (!valCopy)
return E_OUTOFMEMORY;
// free the old value of field and set it to point to the new string
if (*field)
SysFreeString(*field);
*field = valCopy;
// Put together a new URL based on its constituents, if requested
if (fRecomposeUrl)
hr = ComposeUrl();
if (SUCCEEDED(hr))
{
if (bstrCurrentURL)
{
// If the new url is the same as the previous url then we want to navigate but not have it
// add to the history!
if (StrCmpW(bstrCurrentURL,m_bstrFullUrl) == 0)
{
m_fdontputinhistory = TRUE;
}
//
//clean up the old stuff before navigation
//
valCopy = SysAllocString(m_bstrFullUrl);
FreeStuff();
// valCopy can be NULL. does everybody else handle
// the NULL m_bstrFullUrl case?
m_bstrFullUrl = valCopy;
ParseUrl();
SysFreeString(bstrCurrentURL);
}
// Go to the new URL
hr = DoNavigate();
}
return hr;
}
/******************************************************************************
// Derive a new m_bstrUrl and m_bstrFullUrl from its constituents
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmLocation::ComposeUrl()
{
HRESULT hr = S_OK;
ULONG len =
SysStringLen(m_bstrProtocol) +
2 + // //
SysStringLen(m_bstrHostName) +
1 + // trailing /
SysStringLen(m_bstrPort) +
1 + // :
SysStringLen(m_bstrPath) +
1 + // Possible leading /
(m_bstrSearch ? 1 : 0) + // ?
SysStringLen(m_bstrSearch) +
(m_bstrHash ? 1 : 0) + // #
SysStringLen(m_bstrHash) +
10; // Trailing Termination + some slop
BSTR bstrUrl = SafeSysAllocStringLen(L"", len); // allocates len + 1
if (!bstrUrl)
return E_OUTOFMEMORY;
StrCatBuffW(bstrUrl, m_bstrProtocol, len + 1);
StrCatBuffW(bstrUrl, L"//", len + 1);
StrCatBuffW(bstrUrl, m_bstrHostName, len + 1);
if (lstrlenW(m_bstrPort))
{
StrCatBuffW(bstrUrl, L":", len + 1);
StrCatBuffW(bstrUrl, m_bstrPort, len + 1);
}
if (lstrlenW(m_bstrPath))
{
// prepend the leading slash if needed
if (m_bstrPath[0] != '/')
StrCatBuffW(bstrUrl, L"/", len + 1);
StrCatBuffW(bstrUrl, m_bstrPath, len + 1);
}
if (lstrlenW(m_bstrSearch) > 0)
{
StrCatBuffW(bstrUrl, m_bstrSearch, len + 1);
}
if (lstrlenW(m_bstrHash) > 0)
{
StrCatBuffW(bstrUrl, m_bstrHash, len + 1);
}
// OK, everything has succeeded
// Assign to member variables
if (m_bstrFullUrl)
SysFreeString(m_bstrFullUrl);
m_bstrFullUrl = bstrUrl;
return hr;
}
BSTR CIEFrameAuto::COmLocation::ComputeAbsoluteUrl(BSTR bstrUrlRelative)
{
if (FAILED(CheckUrl()))
return 0;
return PrvHTParse(bstrUrlRelative, m_bstrFullUrl, PARSE_ALL);
}
/******************************************************************************
// Tell the window to go to the current URL
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmLocation::DoNavigate()
{
VARIANT v1;
v1.vt = VT_ERROR;
v1.scode = DISP_E_PARAMNOTFOUND;
if (m_fdontputinhistory)
{
v1.vt = VT_I4;
v1.lVal = navNoHistory;
// Reset the flag.
m_fdontputinhistory = FALSE;
}
HRESULT hres = _pAuto->Navigate(m_bstrFullUrl, &v1, PVAREMPTY, PVAREMPTY, PVAREMPTY);
if (hres == HRESULT_FROM_WIN32(ERROR_BUSY))
{
hres = S_OK;
m_fPendingNavigate = TRUE;
}
else
m_fPendingNavigate = FALSE;
return hres;
}
/******************************************************************************
// Parse a URL into its constituents and store them in member variables
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmLocation::ParseUrl()
{
HRESULT hr = S_OK;
BSTR szProtocol = 0,
szHost = 0,
szPath = 0,
szSearch = 0,
szHash = 0,
searchPos = 0,
portPos = 0,
hashPos = 0;
m_bstrSearch = NULL;
// Strip out the search string and the hash string from the URL--
// the parser is too dumb to recognize them
searchPos = StrChrW(m_bstrFullUrl, L'?');
if (searchPos)
{
m_bstrSearch = SysAllocString(searchPos);
*searchPos = 0; // take it away again so it doesn't cause confusion
}
else
{
m_bstrSearch = SysAllocString(L"");
}
if (NULL == m_bstrSearch)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Get the anchor string, including the '#' prefix
hashPos = StrChrW(m_bstrFullUrl, L'#');
if (hashPos)
{
m_bstrHash = SysAllocString(hashPos);
*hashPos = 0; // take it away again so it doesn't cause confusion
}
else
{
m_bstrHash = SysAllocString(L"");
}
if (NULL == m_bstrHash)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Both m_bstrSearch and m_bstrHash can be NULL at this point
// does all the affected code handle this case?
// note there are more cases like this below (m_bstrProtocol for example)
// Parse the protocol
szProtocol = PrvHTParse(m_bstrFullUrl, 0, PARSE_ACCESS | PARSE_PUNCTUATION);
if (!szProtocol)
{
hr = E_OUTOFMEMORY;
goto exit;
}
m_bstrProtocol = SysAllocString(szProtocol);
if (NULL == m_bstrProtocol)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Parse the host name and port number (if any)
// First look for a port
szHost = PrvHTParse(m_bstrFullUrl, 0, PARSE_HOST);
if (!szHost)
{
hr = E_OUTOFMEMORY;
goto exit;
}
portPos = StrChrW(szHost, L':');
if (portPos)
{
m_bstrHostName = SafeSysAllocStringLen(szHost, (unsigned int)(portPos-szHost));
m_bstrPort = SysAllocString(portPos + 1);
}
else
{
m_bstrHostName = SysAllocString(szHost);
m_bstrPort = SysAllocString(L"");
}
if (NULL == m_bstrHostName || NULL == m_bstrPort)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Parse the path and search string (if any)
szPath = PrvHTParse(m_bstrFullUrl, 0, PARSE_PATH);
if (!szPath)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// If the path doesn't start with a '/' then prepend one - Netscape compatibility
if (StrCmpIW(szProtocol, L"javascript:") && StrCmpIW(szProtocol, L"vbscript:") && szPath[0] != L'/')
{
WCHAR *szPath2 = szPath;
int cchPath = lstrlenW(szPath2)+2;
szPath = SafeSysAllocStringLen(0, cchPath); // allocates +1 char for the terminator
if (szPath)
{
szPath[0] = L'/';
szPath[1] = L'\0';
StrCatBuffW(szPath,szPath2, cchPath+1); //+1 added by alloc above
szPath[cchPath] = 0;
SysFreeString(szPath2);
}
else
szPath = szPath2;
}
m_bstrPath = SysAllocString(szPath);
if (NULL == m_bstrPath)
{
hr = E_OUTOFMEMORY;
goto exit;
}
exit:
// Restore hash and search characters
if (searchPos)
*searchPos = L'?';
if (hashPos)
*hashPos = L'#';
// Have to free these using SysFreeString because they come from PrvHTParse
if (szProtocol)
SysFreeString(szProtocol);
if (szHost)
SysFreeString(szHost);
if (szPath)
SysFreeString(szPath);
if (szHash)
SysFreeString(szHash);
return hr;
}
CIEFrameAuto::COmLocation::~COmLocation()
{
FreeStuff();
}
HRESULT CIEFrameAuto::COmLocation::FreeStuff()
{
if (m_bstrFullUrl)
{
SysFreeString(m_bstrFullUrl);
m_bstrFullUrl = 0;
}
if (m_bstrProtocol)
{
SysFreeString(m_bstrProtocol);
m_bstrProtocol = 0;
}
if (m_bstrHostName)
{
SysFreeString(m_bstrHostName);
m_bstrHostName = 0;
}
if (m_bstrPort)
{
SysFreeString(m_bstrPort);
m_bstrPort = 0;
}
if (m_bstrPath)
{
SysFreeString(m_bstrPath);
m_bstrPath = 0;
}
if (m_bstrSearch)
{
SysFreeString(m_bstrSearch);
m_bstrSearch = 0;
}
if (m_bstrHash)
{
SysFreeString(m_bstrHash);
m_bstrHash = 0;
}
return S_OK;
}
/******************************************************************************
Navigator Object
******************************************************************************/
CIEFrameAuto::COmNavigator::COmNavigator() :
CAutomationStub(MIN_BROWSER_DISPID, MAX_BROWSER_DISPID, TRUE)
{
ASSERT(!_UserAgent);
ASSERT(FALSE == _fLoaded);
}
HRESULT CIEFrameAuto::COmNavigator::Init(CMimeTypes *pMimeTypes, CPlugins *pPlugins, COpsProfile *pProfile)
{
ASSERT(pMimeTypes != NULL);
_pMimeTypes = pMimeTypes;
ASSERT(pPlugins != NULL);
_pPlugins = pPlugins;
ASSERT(pProfile != NULL);
_pProfile = pProfile;
CIEFrameAuto* pauto = IToClass(CIEFrameAuto, _omnav, this);
return CAutomationStub::Init(SAFECAST(this, IOmNavigator*), IID_IOmNavigator, CLSID_HTMLNavigator, pauto);
}
/******************************************************************************
// bradsc 11/5/97
// This method should not use hard coded values. Where can we get this info?
// This method has to use non-unicode junk because of Win95
******************************************************************************/
HRESULT CIEFrameAuto::COmNavigator::LoadUserAgent()
{
_fLoaded = TRUE;
CHAR szUserAgent[MAX_PATH]; // URLMON says the max length of the UA string is MAX_PATH
DWORD dwSize = MAX_PATH;
szUserAgent[0] = '\0';
if (ObtainUserAgentString(0, szUserAgent, &dwSize) == S_OK)
{
// Just figure out the real length since 'size' is ANSI bytes required.
//
_UserAgent = SysAllocStringFromANSI(szUserAgent);
}
return _UserAgent ? S_OK : E_FAIL;
}
HRESULT CIEFrameAuto::COmNavigator::_InternalQueryInterface(REFIID riid, void ** const ppv)
{
ASSERT(!IsEqualIID(riid, IID_IUnknown));
if (IsEqualIID(riid, IID_IOmNavigator))
*ppv = SAFECAST(this, IOmNavigator *);
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
STDMETHODIMP CIEFrameAuto::COmNavigator::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *dispparams, VARIANT *pvarResult, EXCEPINFO *pexcepinfo, UINT *puArgErr)
{
HRESULT hr = CAutomationStub::Invoke(dispid,riid,lcid,wFlags,dispparams,pvarResult,pexcepinfo,puArgErr);
if (hr == DISP_E_MEMBERNOTFOUND
&& (wFlags & DISPATCH_PROPERTYGET)
&& dispid == DISPID_VALUE
&& pvarResult != NULL && dispparams->cArgs == 0)
{
pvarResult->vt = VT_BSTR;
pvarResult->bstrVal = SysAllocString(L"[object Navigator]");
hr = pvarResult->bstrVal ? S_OK : E_OUTOFMEMORY;
}
return hr;
}
HRESULT CIEFrameAuto::COmNavigator::_GetIDispatchExDelegate(IDispatchEx ** const delegate)
{
if (!delegate)
return E_POINTER;
IDispatch *pRootDisp = 0;
HRESULT hr = GetRootDelegate(_pAuto, &pRootDisp);
if (SUCCEEDED(hr))
{
IDispatch *pDelegateDisp = 0;
hr = GetDelegateOnIDispatch(pRootDisp, DISPID_NAVIGATOROBJECT, &pDelegateDisp);
pRootDisp->Release();
if (SUCCEEDED(hr))
{
hr = pDelegateDisp->QueryInterface(IID_PPV_ARG(IDispatchEx, delegate));
pDelegateDisp->Release();
}
}
return hr;
}
// All of these have hard-coded lengths and locations
STDMETHODIMP CIEFrameAuto::COmNavigator::get_appCodeName(BSTR* retval)
{
HRESULT hr;
if (retval)
{
if (!_fLoaded)
LoadUserAgent();
if (_UserAgent)
{
*retval = SafeSysAllocStringLen(_UserAgent, 7);
hr = S_OK;
}
else
{
*retval = SysAllocString(APPCODENAME);
hr = *retval ? S_OK : E_OUTOFMEMORY;
}
}
else
{
hr = S_FALSE;
}
return hr;
}
/******************************************************************************
// bradsch 11/8/96
// We should read this out of the registry instead of hard coding!!
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmNavigator::get_appName(BSTR* retval)
{
*retval = SysAllocString(MSIE);
return *retval ? S_OK : E_OUTOFMEMORY;
}
/******************************************************************************
// Netscape defined appVersion to be everything after
// the first 8 characters in the userAgent string.
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmNavigator::get_appVersion(BSTR* retval)
{
if (retval)
{
if (!_fLoaded)
LoadUserAgent();
if (_UserAgent)
{
// If _UserAgent is less than 8 characters the registry is messed up.
// If _UserAgent is exactly 8 characters we will just return a NULL string.
if (lstrlenW(_UserAgent) < 8)
*retval = SysAllocString(L"");
else
*retval = SysAllocString(_UserAgent + 8);
return *retval ? S_OK : E_OUTOFMEMORY;
}
*retval = SysAllocString(APPVERSION);
return *retval ? S_OK : E_OUTOFMEMORY;
}
else
{
return S_FALSE;
}
}
STDMETHODIMP CIEFrameAuto::COmNavigator::get_userAgent(BSTR* retval)
{
if (retval)
{
if (!_fLoaded)
LoadUserAgent();
if (_UserAgent)
{
*retval = SysAllocString(_UserAgent);
}
else
{
*retval = SysAllocString(USERAGENT);
}
return *retval ? S_OK : E_OUTOFMEMORY;
}
else
{
return S_FALSE;
}
}
STDMETHODIMP CIEFrameAuto::COmNavigator::get_cookieEnabled(VARIANT_BOOL* enabled)
{
HRESULT hr = E_POINTER;
if (enabled)
{
BSTR strUrl;
*enabled = VARIANT_FALSE;
hr = _pAuto->_omloc.get_href(&strUrl);
if (SUCCEEDED(hr))
{
DWORD dwPolicy;
if (SUCCEEDED(ZoneCheckUrlExW(strUrl, &dwPolicy, sizeof(dwPolicy), NULL, NULL,
URLACTION_COOKIES_ENABLED, PUAF_NOUI, NULL)) &&
(URLPOLICY_DISALLOW != dwPolicy))
{
*enabled = VARIANT_TRUE;
}
SysFreeString(strUrl);
}
else
ASSERT(!strUrl); // If this failed and strUrl isn't NULL, then we are leaking.
}
return hr;
}
STDMETHODIMP CIEFrameAuto::COmNavigator::javaEnabled(VARIANT_BOOL* enabled)
{
HRESULT hr = E_POINTER;
if (enabled)
{
BSTR strUrl;
*enabled = VARIANT_FALSE;
hr = _pAuto->_omloc.get_href(&strUrl);
if (SUCCEEDED(hr))
{
DWORD dwPolicy;
if (SUCCEEDED(ZoneCheckUrlExW(strUrl, &dwPolicy, sizeof(dwPolicy), NULL, NULL,
URLACTION_JAVA_PERMISSIONS, PUAF_NOUI, NULL)) &&
(URLPOLICY_JAVA_PROHIBIT != dwPolicy))
{
*enabled = VARIANT_TRUE;
}
SysFreeString(strUrl);
}
else
ASSERT(!strUrl); // If this failed and strUrl isn't NULL, then we are leaking.
}
return hr;
}
STDMETHODIMP CIEFrameAuto::COmNavigator::taintEnabled (VARIANT_BOOL *pfEnabled)
{
if (pfEnabled)
{
*pfEnabled = VARIANT_FALSE;
}
else
return E_POINTER;
return S_OK;
}
STDMETHODIMP CIEFrameAuto::COmNavigator::get_mimeTypes (IHTMLMimeTypesCollection**ppMimeTypes)
{
if (ppMimeTypes)
{
*ppMimeTypes = _pMimeTypes;
_pMimeTypes->AddRef();
return S_OK;
}
else
return E_POINTER;
}
/******************************************************************************
// member: toString method
// Synopsis : we need to invoke on dispid_value, and coerce the result into
// a bstr.
//
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmNavigator::toString(BSTR * pbstr)
{
HRESULT hr = E_POINTER;
if (pbstr)
{
*pbstr= SysAllocString(L"[object Navigator]");
if (!*pbstr)
hr = E_OUTOFMEMORY;
else
hr = S_OK;
}
return hr;
}
CIEFrameAuto::CCommonCollection::CCommonCollection() :
CAutomationStub(MIN_BROWSER_DISPID, MAX_BROWSER_DISPID, TRUE)
{
}
HRESULT CIEFrameAuto::CMimeTypes::Init()
{
CIEFrameAuto* pauto = IToClass(CIEFrameAuto, _mimeTypes, this);
return CAutomationStub::Init(SAFECAST(this, IHTMLMimeTypesCollection*), IID_IHTMLMimeTypesCollection,
CLSID_CMimeTypes, pauto);
}
HRESULT CIEFrameAuto::CCommonCollection::_GetIDispatchExDelegate(IDispatchEx ** const delegate)
{
if (!delegate)
return E_POINTER;
// We do not handle expandos yet
*delegate = NULL;
return DISP_E_MEMBERNOTFOUND;
}
HRESULT CIEFrameAuto::CMimeTypes::_InternalQueryInterface(REFIID riid, void ** const ppv)
{
if (IsEqualIID(riid, IID_IHTMLMimeTypesCollection))
*ppv = SAFECAST(this, IHTMLMimeTypesCollection *);
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
HRESULT CIEFrameAuto::CCommonCollection::GetDispID(BSTR bstrName, DWORD grfdex, DISPID *pid)
{
HRESULT hr;
hr = CAutomationStub::GetDispID(bstrName, grfdex, pid);
if (hr == DISP_E_MEMBERNOTFOUND)
{
// We ignore the command we do not understand
*pid = DISPID_UNKNOWN;
hr = S_OK;
}
return hr;
}
HRESULT CIEFrameAuto::CCommonCollection::InvokeEx(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
{
if (id == DISPID_UNKNOWN && pvarRes)
{
V_VT(pvarRes) = VT_EMPTY;
return S_OK;
}
return CAutomationStub::InvokeEx(id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
}
HRESULT CIEFrameAuto::CCommonCollection::get_length(LONG* pLength)
{
if (pLength == NULL)
return E_POINTER;
*pLength = 0;
return S_OK;
}
HRESULT CIEFrameAuto::COmNavigator::get_plugins (IHTMLPluginsCollection **ppPlugins)
{
if (ppPlugins)
{
*ppPlugins = _pPlugins;
_pPlugins->AddRef();
return S_OK;
}
else
return E_POINTER;
}
HRESULT CIEFrameAuto::COmNavigator::get_opsProfile (IHTMLOpsProfile **ppOpsProfile)
{
if (ppOpsProfile)
{
*ppOpsProfile = _pProfile;
(*ppOpsProfile)->AddRef();
return S_OK;
}
else
return E_POINTER;
}
HRESULT CIEFrameAuto::COmNavigator::get_cpuClass(BSTR * p)
{
if (p)
{
SYSTEM_INFO SysInfo;
::GetSystemInfo(&SysInfo);
switch(SysInfo.wProcessorArchitecture)
{
case PROCESSOR_ARCHITECTURE_INTEL:
*p = SysAllocString(L"x86");
break;
case PROCESSOR_ARCHITECTURE_AMD64:
*p = SysAllocString(L"AMD64");
break;
case PROCESSOR_ARCHITECTURE_IA64:
*p = SysAllocString(L"IA64");
break;
default:
*p = SysAllocString(L"Other");
break;
}
if (*p == NULL)
return E_OUTOFMEMORY;
else
return S_OK;
}
else
return E_POINTER;
}
#define MAX_VERSION_STRING 30
HRESULT CIEFrameAuto::COmNavigator::get_systemLanguage(BSTR * p)
{
HRESULT hr = E_POINTER;
if (p)
{
LCID lcid;
WCHAR strVer[MAX_VERSION_STRING];
*p = NULL;
lcid = ::GetSystemDefaultLCID();
hr = LcidToRfc1766W(lcid, strVer, MAX_VERSION_STRING);
if (!hr)
{
*p = SysAllocString(strVer);
if (!*p)
hr = E_OUTOFMEMORY;
}
}
return hr;
}
HRESULT CIEFrameAuto::COmNavigator::get_browserLanguage(BSTR * p)
{
LCID lcid =0;
LANGID lidUI;
WCHAR strVer[MAX_VERSION_STRING];
HRESULT hr;
if (!p)
{
return E_POINTER;
}
*p = NULL;
lidUI = MLGetUILanguage();
lcid = MAKELCID(lidUI, SORT_DEFAULT);
hr = LcidToRfc1766W(lcid, strVer, MAX_VERSION_STRING);
if (!hr)
{
*p = SysAllocString(strVer);
if (!*p)
return E_OUTOFMEMORY;
else
{
return S_OK;
}
}
return E_INVALIDARG;
}
HRESULT CIEFrameAuto::COmNavigator::get_userLanguage(BSTR * p)
{
HRESULT hr = E_POINTER;
if (p)
{
LCID lcid;
WCHAR strVer[MAX_VERSION_STRING];
*p = NULL;
lcid = ::GetUserDefaultLCID();
hr = LcidToRfc1766W(lcid, strVer, MAX_VERSION_STRING);
if (!hr)
{
*p = SysAllocString(strVer);
if (!*p)
hr = E_OUTOFMEMORY;
}
}
return hr;
}
HRESULT CIEFrameAuto::COmNavigator::get_platform(BSTR * p)
{
// Nav compatability item, returns the following in Nav:-
// Win32,Win16,Unix,Motorola,Max68k,MacPPC
// shdocvw is Win32 only, so
if (p)
{
*p = SysAllocString (L"Win32");
return *p ? S_OK : E_OUTOFMEMORY;
}
else
return E_POINTER;
}
HRESULT CIEFrameAuto::COmNavigator::get_appMinorVersion(BSTR * p)
{
HKEY hkInetSettings;
long lResult;
HRESULT hr = S_FALSE;
if (!p)
{
return E_POINTER;
}
*p = NULL;
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
0, KEY_QUERY_VALUE, &hkInetSettings);
if (ERROR_SUCCESS == lResult)
{
DWORD dwType;
TCHAR buffer[MAX_URL_STRING];
DWORD size = sizeof(buffer);
// If this is bigger than MAX_URL_STRING the registry is probably hosed.
lResult = RegQueryValueEx(hkInetSettings, TEXT("MinorVersion"), 0, &dwType, (BYTE*)buffer, &size);
RegCloseKey(hkInetSettings);
if (ERROR_SUCCESS == lResult && dwType == REG_SZ)
{
// Just figure out the real length since 'size' is ANSI bytes required.
*p = SysAllocString(buffer);
hr = *p ? S_OK : E_OUTOFMEMORY;
}
}
if (S_OK != hr)
{
*p = SysAllocString (L"0");
hr = *p ? S_OK : E_OUTOFMEMORY;
}
return hr;
}
HRESULT CIEFrameAuto::COmNavigator::get_connectionSpeed(long * p)
{
if (p)
{
*p = NULL;
return E_NOTIMPL;
}
else
return E_POINTER;
}
HRESULT CIEFrameAuto::COmNavigator::get_onLine(VARIANT_BOOL * p)
{
if (p)
{
*p = TO_VARIANT_BOOL(!IsGlobalOffline());
return S_OK;
}
else
return E_POINTER;
}
HRESULT CIEFrameAuto::CPlugins::Init()
{
CIEFrameAuto* pauto = IToClass(CIEFrameAuto, _plugins, this);
return CAutomationStub::Init(SAFECAST(this, IHTMLPluginsCollection*), IID_IHTMLPluginsCollection,
CLSID_CPlugins, pauto);
}
HRESULT CIEFrameAuto::CPlugins::_InternalQueryInterface(REFIID riid, void ** const ppv)
{
if (IsEqualIID(riid, IID_IHTMLPluginsCollection))
*ppv = SAFECAST(this, IHTMLPluginsCollection *);
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
/******************************************************************************
Window Open Support
******************************************************************************/
CIEFrameAuto::COmHistory::COmHistory() :
CAutomationStub(MIN_BROWSER_DISPID, MAX_BROWSER_DISPID, TRUE)
{
}
HRESULT CIEFrameAuto::COmHistory::Init()
{
CIEFrameAuto* pauto = IToClass(CIEFrameAuto, _omhist, this);
return CAutomationStub::Init(SAFECAST(this, IOmHistory*), IID_IOmHistory, CLSID_HTMLHistory, pauto);
}
HRESULT CIEFrameAuto::COmHistory::_InternalQueryInterface(REFIID riid, void ** const ppv)
{
ASSERT(!IsEqualIID(riid, IID_IUnknown));
if (IsEqualIID(riid, IID_IOmHistory))
*ppv = SAFECAST(this, IOmHistory *);
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
HRESULT CIEFrameAuto::COmHistory::_GetIDispatchExDelegate(IDispatchEx ** const delegate)
{
if (!delegate)
return E_POINTER;
IDispatch *pRootDisp = 0;
HRESULT hr = GetRootDelegate(_pAuto, &pRootDisp);
if (SUCCEEDED(hr))
{
IDispatch *pDelegateDisp = 0;
hr = GetDelegateOnIDispatch(pRootDisp, DISPID_HISTORYOBJECT, &pDelegateDisp);
pRootDisp->Release();
if (SUCCEEDED(hr))
{
hr = pDelegateDisp->QueryInterface(IID_IDispatchEx, (void**)delegate);
pDelegateDisp->Release();
}
}
return hr;
}
/******************************************************************************
// I just tested Nav3 and they simply ignore parameters to back() and forward. They
// do, however, honor the value passed to go(). Hey... Netscape actually followed
// their documented behavior for once!
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmHistory::back(VARIANT*)
{
//
// Netscape ignores all errors from these navigation functions
//
_pAuto->GoBack();
return S_OK;
}
STDMETHODIMP CIEFrameAuto::COmHistory::forward(VARIANT*)
{
//
// Netscape ignores all errors from these navigation functions
//
_pAuto->GoForward();
return S_OK;
}
/******************************************************************************
Get History Length from TravelLog
******************************************************************************/
STDMETHODIMP CIEFrameAuto::COmHistory::get_length(short* retval)
{
// Make sure we have an IBrowserService pointer
if (_pAuto->_pbs==NULL)
{
TraceMsg(DM_WARNING, "CIEA::history.go called _pbs==NULL");
return E_FAIL;
}
*retval = 0;
// The new ITravelLog
ITravelLog *ptl;
// Get the new TravelLog from the browser service object.
if (SUCCEEDED(_pAuto->_pbs->GetTravelLog(&ptl)))
{
if (ptl)
*retval = (short)ptl->CountEntries(_pAuto->_pbs);
ptl->Release();
}
return S_OK;
}
STDMETHODIMP CIEFrameAuto::COmHistory::go(VARIANT *pVargDist)
{
// Parameter is optional. If not present, just refresh.
if (pVargDist->vt == VT_ERROR
&& pVargDist->scode == DISP_E_PARAMNOTFOUND)
return _pAuto->Refresh();
// Change type to short if possible.
//
HRESULT hr = VariantChangeType(pVargDist, pVargDist, NULL, VT_I2);
if (SUCCEEDED(hr))
{
//
// If 0, just call Refresh
//
if (pVargDist->iVal == 0)
{
return _pAuto->Refresh();
}
// Make sure we have an IBrowserService pointer
if (_pAuto->_pbs==NULL)
{
TraceMsg(DM_WARNING, "CIEA::history.go called _pbs==NULL");
return E_FAIL;
}
// The new ITravelLog
ITravelLog *ptl;
// Get the new TravelLog from the browser service object.
if (SUCCEEDED(_pAuto->_pbs->GetTravelLog(&ptl)))
{
// Tell it to travel. Pass in the IShellBrowser pointer.
ptl->Travel(_pAuto->_pbs, pVargDist->iVal);
ptl->Release();
}
return S_OK;
}
// Now see if it's a string.
//
if (pVargDist->vt == VT_BSTR)
{
LPITEMIDLIST pidl;
ITravelLog *ptl;
ITravelEntry *pte;
// Make sure we have an IBrowserService pointer
if (_pAuto->_pbs==NULL)
{
TraceMsg(DM_WARNING, "CIEA::history.go called _pbs==NULL");
return E_FAIL;
}
if (SUCCEEDED(_pAuto->_PidlFromUrlEtc(CP_ACP, pVargDist->bstrVal, NULL, &pidl)))
{
if (SUCCEEDED(_pAuto->_pbs->GetTravelLog(&ptl)))
{
if (SUCCEEDED(ptl->FindTravelEntry(_pAuto->_pbs, pidl, &pte)))
{
pte->Invoke(_pAuto->_pbs);
pte->Release();
}
ptl->Release();
}
ILFree(pidl);
}
}
//
// Netscape ignores all errors from these navigation functions
//
return S_OK;
}
/******************************************************************************
Window Open Support
******************************************************************************/
DWORD OpenAndNavigateToURL(
CIEFrameAuto *pauto, // IEFrameAuto of caller. Used to get IWeBrowserApp, ITargetFrame2, and IHlinkFrame methods
BSTR *pbstrURL, // URL to navigate to. Should already be an escaped absolute URL
const WCHAR *pwzTarget, // Name of the frame to navigate
ITargetNotify *pNotify, // Received callback on open. May be NULL
BOOL bNoHistory, // Don't add to history
BOOL bSilent) // This frame is in silent Mode
{
ASSERT(*pbstrURL);
ASSERT(pwzTarget);
ASSERT(pauto);
IUnknown *punkTargetFrame = NULL;
LPTARGETFRAMEPRIV ptgfpTarget = NULL;
BOOL fOpenInNewWindow = FALSE;
LPBINDCTX pBindCtx = NULL;
LPMONIKER pMoniker = NULL;
LPHLINK pHlink = NULL;
DWORD dwHlinkFlags = 0;
DWORD zone_cross = 0;
const WCHAR *pwzFindLoc = 0;
// Used to open a new window if there is not an existing frame
LPTARGETFRAMEPRIV ptgfp = SAFECAST(pauto, ITargetFramePriv*);
// Lookup the frame cooresponding to the target - this will give us the
// IUnknown for an object that can give us the coresponding IHlinkFrame
// via IServiceProvider::QueryService.
HRESULT hr = pauto->FindFrame(pwzTarget, FINDFRAME_JUSTTESTEXISTENCE, &punkTargetFrame);
if (punkTargetFrame)
{
// Get the IHlinkFrame for the target'ed frame.
hr = punkTargetFrame->QueryInterface(IID_PPV_ARG(ITargetFramePriv, &ptgfpTarget));
if (FAILED(hr))
goto Exit;
ptgfp = ptgfpTarget;
// if URL is empty
if (!**pbstrURL || **pbstrURL == EMPTY_URL)
{
LPTARGETNOTIFY ptgnNotify = NULL;
if (pNotify)
{
if (FAILED(pNotify->QueryInterface(IID_PPV_ARG(ITargetNotify, &ptgnNotify))))
ptgnNotify = NULL;
}
if (ptgnNotify)
{
ptgnNotify->OnReuse(punkTargetFrame);
ptgnNotify->Release();
}
goto Exit; // Don't navigate.
}
}
else if (SUCCEEDED(hr))
{
// No luck, open in new window
fOpenInNewWindow = TRUE;
// Now, if the URL is empty, replace it with "about:blank"
if (!**pbstrURL || **pbstrURL == EMPTY_URL)
{
BSTR bstrOldURL = *pbstrURL;
*pbstrURL = NULL;
if (*bstrOldURL == EMPTY_URL)
// The URL is really empty string however when the 0x01 is the
// character of the URL this signals that the security information
// follows. Therefore, we'll need to append the about:blank +
// \1 + callerURL.
CreateBlankURL(pbstrURL, TEXT("about:blank"), bstrOldURL);
else
CreateBlankURL(pbstrURL, pauto->_fDesktopComponent() ? NAVFAIL_URL_DESKTOPITEM : NAVFAIL_URL, bstrOldURL);
SysFreeString(bstrOldURL);
}
}
else
goto Exit;
// bradsch 11/12/96
// Need to figure out Browser-Control stuff for webcheck
// 11/12/96
// Need to implment this with Trident... I think "JavaScript:" should be
// supported as a real protocol. This would provide greater Navigator
// compatibility and allows us to avoid the following hack.
/*
if (!StrCmpNI(pszURL, JAVASCRIPT_PROTOCOL, ARRAY_ELEMENTS(JAVASCRIPT_PROTOCOL)-1))
{
if (tw && tw->w3doc && DLCtlShouldRunScripts(tw->lDLCtlFlags))
ScriptOMExecuteThis(tw->w3doc->dwScriptHandle, JAVASCRIPT, &pszURL[ARRAY_ELEMENTS(JAVASCRIPT_PROTOCOL)-1],
pszJavascriptTarget);
return ERROR_SUCCESS;
}
*/
LONG_PTR hwnd;
hr = pauto->get_HWND(&hwnd);
if (FAILED(hr))
goto Exit;
BSTR bstrCurrentURL;
hr = pauto->get_LocationURL(&bstrCurrentURL);
if (FAILED(hr))
goto Exit;
zone_cross = ERROR_SUCCESS;
if (!bSilent)
{
ASSERT(pauto->_psb);
if (pauto->_psb)
pauto->_psb->EnableModelessSB(FALSE);
zone_cross = InternetConfirmZoneCrossing((HWND) hwnd, bstrCurrentURL, *pbstrURL, FALSE);
if (pauto->_psb)
pauto->_psb->EnableModelessSB(TRUE);
}
SysFreeString(bstrCurrentURL);
if (ERROR_CANCELLED == zone_cross)
{
hr = HRESULT_FROM_WIN32(zone_cross);
goto Exit;
}
// create a moniker and bind context for this URL
// use CreateAsyncBindCtxEx so that destination still navigates
// even if we exit, as in the following code:
// window.close()
// window.open("http://haha/jokesonyou.html","_blank");
hr = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, &pBindCtx, 0);
if (FAILED(hr))
goto Exit;
if (pNotify)
{
hr = pBindCtx->RegisterObjectParam(TARGET_NOTIFY_OBJECT_NAME, pNotify);
ASSERT(SUCCEEDED(hr));
}
// Seperate the base URL from the location (hash)
if (pwzFindLoc = StrChrW(*pbstrURL, '#'))
{
const WCHAR *pwzTemp = StrChrW(pwzFindLoc, '/');
if (!pwzTemp)
pwzTemp = StrChrW(pwzFindLoc, '\\');
// no delimiters past this # marker... we've found a location.
// break out
if (pwzTemp)
pwzFindLoc = NULL;
}
WCHAR wszBaseURL[MAX_URL_STRING+1];
WCHAR wszLocation[MAX_URL_STRING+1];
if (pwzFindLoc)
{
// StrCpyNW alway null terminates to we need to copy len+1
int cchCopy = (int)(pwzFindLoc-*pbstrURL+1);
if (cchCopy > ARRAYSIZE(wszBaseURL))
cchCopy = ARRAYSIZE(wszBaseURL);
StrCpyNW(wszBaseURL, *pbstrURL, cchCopy);
StrCpyNW(wszLocation, pwzFindLoc, ARRAYSIZE(wszLocation));
}
else
{
StrCpyNW(wszBaseURL, *pbstrURL, ARRAYSIZE(wszBaseURL));
wszLocation[0] = 0;
}
ASSERT(pBindCtx);
if (fOpenInNewWindow)
{
dwHlinkFlags |= HLNF_OPENINNEWWINDOW;
}
if (bNoHistory)
{
dwHlinkFlags |= HLNF_CREATENOHISTORY;
}
hr = ptgfp->NavigateHack(dwHlinkFlags,
pBindCtx,
NULL,
fOpenInNewWindow ? pwzTarget : NULL,
wszBaseURL,
pwzFindLoc ? wszLocation : NULL);
Exit:
SAFERELEASE(ptgfpTarget);
SAFERELEASE(punkTargetFrame);
SAFERELEASE(pBindCtx);
return hr;
}
HRESULT CreateBlankURL(BSTR *url, LPCTSTR pszErrorUrl, BSTR oldUrl)
{
ASSERT(url);
unsigned int cbTotal = 0;
if (pszErrorUrl)
cbTotal = lstrlen(pszErrorUrl);
if (oldUrl) // Security portion of URL to append.
cbTotal += lstrlenW(oldUrl);
if (cbTotal)
{
*url = SysAllocStringByteLen(NULL, cbTotal * sizeof(WCHAR)); // adds +1 to cbTotal
if (*url)
{
StrCpyN(*url, pszErrorUrl, cbTotal + 1);
// Append the security URL to the actual URL.
if (oldUrl)
{
StrCatBuffW(*url, oldUrl, cbTotal + 1);
}
return S_OK;
}
}
return E_FAIL;
}
// bradsch 11/14/96
// This parsing code was copied from MSHTML and really bites. It should be replaced.
BOOL GetNextOption(BSTR& bstrOptionString, BSTR* optionName, int* piValue)
{
WCHAR* delimiter;
// Get the name of the option being set
*optionName = GetNextToken(bstrOptionString, L"=,", L" \t\n\r", &delimiter);
BSTR optionSetting = NULL;
if (!*optionName)
return FALSE;
// If there is an equal sign, get the value being set
if (*delimiter=='=')
optionSetting = GetNextToken(delimiter+1, L"=,", L" \t\n\r", &delimiter);
if (!optionSetting)
*piValue = TRUE;
else
{
if (StrCmpIW(optionSetting, L"yes")==0)
*piValue = 1; // TRUE
else if (StrCmpIW(optionSetting, L"no")==0)
*piValue = 0; // FALSE
else
{
*piValue = StrToIntW(optionSetting);
}
SysFreeString(optionSetting);
}
// Advance the option string to the delimiter
bstrOptionString=delimiter;
return TRUE;
}
/******************************************************************************
// Return the next token, or NULL if there are no more tokens
******************************************************************************/
BSTR GetNextToken(BSTR bstr, BSTR delimiters, BSTR whitespace, BSTR *nextPos)
{
BSTR result = NULL;
WCHAR* curPos = bstr;
// skip delimiters and whitespace to get the start of the token
while (*curPos && (StrChrW(delimiters, *curPos) || StrChrW(whitespace, *curPos)))
curPos++;
WCHAR* start = curPos;
// keep scanning until we reach another delimiter or whitespace
while (*curPos && !StrChrW(delimiters, *curPos) && !StrChrW(whitespace, *curPos))
curPos++;
if (curPos > start)
{
// copy out the token as the result
result = SafeSysAllocStringLen(start, (int)(curPos-start)); // allocates +1 for the terminator
}
// scan to past the whitespace to the next delimiter
while (*curPos && StrChrW(whitespace, *curPos))
curPos++;
// return the delimiter
*nextPos = curPos;
return result;
}
#define MAX_ARGS 10
HRESULT __cdecl DoInvokeParamHelper(IUnknown* punk, IConnectionPoint* pccp,
BOOL *pf, void **ppv, DISPID dispid, UINT cArgs, ...
/* param pairs of: LPVOID Arg, VARENUM Type, ... */)
{
HRESULT hr;
IShellBrowser * psb = NULL;
if (punk && S_OK == punk->QueryInterface(IID_PPV_ARG(IShellBrowser, &psb)))
psb->EnableModelessSB(FALSE);
// Calling with no params is wasteful, they should call DoInvoke directly
//
if (cArgs == 0)
{
// Can't possible cancel if there are no parameters
ASSERT(pf == NULL && ppv == NULL);
IConnectionPoint_SimpleInvoke(pccp, dispid, NULL);
hr = S_OK;
}
else if (cArgs < MAX_ARGS)
{
// This function can potentially get called *very frequently*. It is
// used, among other things, to set status text and progress barometer
// values. We need to make an array of VARIANTARGs to hold a variable
// number of parameters. As an optimization since we want to minimize
// overhead in this function, we will use a static array on the stack
// rather than allocating memory. This puts a limit (of MAX_ARGS) on
// the number of arguments this function can process; but this is just
// an internal function so that's OK. Bump up MAX_ARGS if you run out of
// room.
VARIANTARG VarArgList[MAX_ARGS];
DISPPARAMS dispparams = {0};
va_list ArgList;
va_start(ArgList, cArgs);
hr = SHPackDispParamsV(&dispparams, VarArgList, cArgs, ArgList);
va_end(ArgList);
// Now Simply Call The DoInvoke to do the real work...
if (S_OK == hr)
IConnectionPoint_InvokeWithCancel(pccp, dispid, &dispparams, pf, ppv);
hr = S_OK;
}
else
{
hr = E_UNEXPECTED;
}
if (psb)
{
psb->EnableModelessSB(TRUE);
SAFERELEASE(psb);
}
return hr;
}