Windows2003-3790/inetcore/mshtml/iextag/ancrclk.cxx
2020-09-30 16:53:55 +02:00

515 lines
15 KiB
C++

//=================================================
//
// File : ancrclk.cxx
//
// purpose : implementation of the
// CAnchorClick class
// Gives anchor tags the ability to
// navigate to web folders
//
//=================================================
// Chad Lindhorst, 1998
#include "headers.h"
#pragma MARK_DATA(__FILE__)
#pragma MARK_CODE(__FILE__)
#pragma MARK_CONST(__FILE__)
#include "ancrclk.h"
#include "httpwfh.h"
#include "utils.hxx"
// ========================================================================
// CAnchorClick
// ========================================================================
//+------------------------------------------------------------------------
//
// Members: CAnchorClick::CAnchorClick
// CAnchorClick::~CAnchorClick
//
// Synopsis: Constructor/destructor
//
//-------------------------------------------------------------------------
CAnchorClick::CAnchorClick()
{
m_pSite = NULL;
m_pSink = NULL;
m_pSinkContextMenu = NULL;
}
CAnchorClick::~CAnchorClick()
{
if (m_pSite)
m_pSite->Release();
if (m_pSink)
delete m_pSink;
if (m_pSinkContextMenu)
delete m_pSinkContextMenu;
}
// ========================================================================
// IAnchorClick
// ========================================================================
//+------------------------------------------------------------------------
//
// Member: CAnchorClick::ProcOnClick
//
// Synopsis: Handles the onclick events.
//
//-------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE
CAnchorClick::ProcOnClick ()
{
//BSTR bstrProtocol = NULL; //bug 50463
BSTR bstrTarget = NULL;
BSTR bstrUrl = NULL;
HRESULT hr = E_FAIL;
IHTMLElement *pElem = NULL;
IElementBehavior * pPeer = NULL;
Iwfolders * pWF = NULL;
CComObject<Cwfolders> *pInstance = NULL;
IHTMLEventObj * pEvent = NULL;
IHTMLWindow2 * pWin = NULL;
if (FAILED(hr = m_pSite->GetElement (&pElem)))
goto cleanup;
if ( SUCCEEDED(hr = GetProperty_BSTR (pElem, L"href", &bstrUrl)))
//bug 50463 && SUCCEEDED(hr = GetProperty_BSTR (pElem, L"navType", &bstrProtocol)) )
{
VARIANT vFalse;
vFalse.vt = VT_BOOL;
vFalse.boolVal = FALSE;
/* //bug 50463
if ((StrCmpIW (bstrProtocol, L"any")) &&
(StrCmpIW (bstrProtocol, L"dav")) &&
(StrCmpIW (bstrProtocol, L"wec")))
{
// this is a bad protocol. Let's get outta here.
goto cleanup;
}
*/
// if we got this far, we are gonna do a folder navigate
// prevent us from getting handled by anyone else.
if (FAILED(hr = GetHTMLWindow (m_pSite, &pWin)))
goto cleanup;
if (FAILED(hr = pWin->get_event (&pEvent)) ||
FAILED(hr = pEvent->put_returnValue(vFalse)))
{
goto cleanup;
}
// sets the target frame
hr = GetProperty_BSTR (pElem, L"target", &bstrTarget);
if (FAILED(hr) || !bstrTarget)
bstrTarget = NULL;
// get a hold of the httpFolder behavior.
if (FAILED(hr = CComObject<Cwfolders>::CreateInstance(&pInstance)) ||
FAILED(hr = pInstance->QueryInterface(IID_Iwfolders, (void **)&pWF)))
{
goto cleanup;
}
{
IUnknown * punk = NULL;
HWND hwnd = 0;
// gets browser window handle (for ui)
hr = GetClientSiteWindow(m_pSite, &hwnd);
hr = IUnknown_QueryService(m_pSite, SID_SWebBrowserApp, IID_IUnknown,
(LPVOID *) &punk);
// navigates to the folder view of the url specified
hr = pWF->navigateNoSite (bstrUrl, bstrTarget, /*bstrProtocol,*/ (DWORD)(DWORD_PTR)hwnd, punk);
}
}
else
hr = S_OK; // since the navType wasn't set, and no we ignore everything
cleanup:
SysFreeString (bstrTarget);
SysFreeString (bstrUrl);
//SysFreeString (bstrProtocol);
ReleaseInterface (pEvent);
ReleaseInterface (pWin);
ReleaseInterface (pElem);
ReleaseInterface (pWF);
ReleaseInterface (pPeer);
return hr;
}
// ========================================================================
// IElementBehavior
// ========================================================================
//+------------------------------------------------------------------------
//
// Member: CAnchorClick::Init
//
// Synopsis: Called when this code is initialized as a behavior
//
//-------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE
CAnchorClick::Init (IElementBehaviorSite __RPC_FAR *pBehaviorSite)
{
HRESULT hr = E_INVALIDARG;
BSTR bstrEvent = NULL;
BSTR bstronContextMenu = NULL;
BSTR bstrUrl = NULL;
//bug 50463 BSTR bstrProtocol = NULL;
VARIANT_BOOL vSuccess = VARIANT_FALSE;
IHTMLElement *pElem = NULL;
IHTMLElement2 *pElem2 = NULL;
// this puppy is ref counted when used.
m_pSink = new CEventSink (this);
m_pSinkContextMenu = new CEventSink (this);
if (!m_pSink || !m_pSinkContextMenu)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
if (pBehaviorSite != NULL)
{
m_pSite = pBehaviorSite;
m_pSite->AddRef();
}
if (FAILED(hr = m_pSite->GetElement (&pElem)))
goto cleanup;
hr = pElem->QueryInterface(IID_IHTMLElement2, (void **)&pElem2);
if (FAILED(hr))
goto cleanup;
// we are adding a phony href attribute to the tag if there is
// a folder attribute set. This will make sure that the
// browser uses the right underlining and colors for anchors
// that have no href attribute, but do have a folder attribute.
if ( SUCCEEDED(hr = GetProperty_BSTR (pElem, L"folder", &bstrUrl)))
/* && (FAILED(hr = GetProperty_BSTR (pElem, L"navType", &bstrProtocol)) ||
((!StrCmpIW (bstrProtocol, L"any")) ||
(!StrCmpIW (bstrProtocol, L"dav")) ||
(!StrCmpIW (bstrProtocol, L"wec")))) )
*/
{
VARIANT vbstrUrl;
vbstrUrl.vt = VT_BSTR;
vbstrUrl.bstrVal = bstrUrl;
pElem->setAttribute (L"href", vbstrUrl, VARIANT_FALSE);
}
else
{
// If there is no folder specified then we assume this to be a regular anchor tag
// Bug 54304
goto cleanup;
}
/*
// now we add a navtype if one wasn't specified and there is a "folder"
// we add the default "any" protocol
if ( bstrUrl && !bstrProtocol)
{
VARIANT vbstrUrl;
vbstrUrl.vt = VT_BSTR;
vbstrUrl.bstrVal = SysAllocString (L"any");
if (!V_BSTR(&vbstrUrl))
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
pElem->setAttribute (L"navType", vbstrUrl, VARIANT_FALSE);
SysFreeString (vbstrUrl.bstrVal);
}
*/
// we want to sink a few events.
// we will take over the click and mouseover events because they
// act differently for folder view anchors
bstrEvent = SysAllocString (L"onclick");
if (!bstrEvent)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
pElem2->attachEvent (bstrEvent, (IDispatch *) m_pSink, &vSuccess);
if (vSuccess == VARIANT_TRUE)
hr = S_OK;
else
{
hr = E_FAIL;
goto cleanup;
}
bstronContextMenu = SysAllocString(L"oncontextmenu");
if (bstronContextMenu) {
pElem2->attachEvent (bstronContextMenu, (IDispatch *) m_pSinkContextMenu, &vSuccess);
if (vSuccess == VARIANT_TRUE)
hr = S_OK;
else
{
hr = E_FAIL;
goto cleanup;
}
}
cleanup:
ReleaseInterface (pElem);
ReleaseInterface (pElem2);
SysFreeString (bstrEvent);
SysFreeString (bstronContextMenu);
SysFreeString (bstrUrl);
return hr;
}
//+------------------------------------------------------------------------
//
// Member: CAnchorClick::Notify
//
// Synopsis: Not really used, but needed by the interface...
//
//-------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE
CAnchorClick::Notify (LONG lEvent, VARIANT __RPC_FAR *pVar)
{
return S_OK;
}
//+------------------------------------------------------------------------
//
// Member: CAnchorClick::GetProperty_Variant
//
// Synopsis: Gets a property from the element passed in as pDisp.
// Taken from \mshtml\src\f3\drt\activex\peerdecl
//
//-------------------------------------------------------------------------
HRESULT
CAnchorClick::GetProperty_Variant (IDispatch * pDisp, LPWSTR pchName, VARIANT * pvarRes)
{
HRESULT hr = S_OK;
DISPID dispid;
EXCEPINFO excepinfo;
UINT nArgErr;
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
if (!pvarRes || !pDisp)
return E_POINTER;
hr = pDisp->GetIDsOfNames(IID_NULL, &pchName, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if (hr)
goto Cleanup;
hr = pDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET,
&dispparams, pvarRes, &excepinfo, &nArgErr);
Cleanup:
return hr;
}
//+------------------------------------------------------------------------
//
// Member: CAnchorClick::GetProperty_BSTR
//
// Synopsis: Gets a property from the element passed in as pDisp.
// Taken from \mshtml\src\f3\drt\activex\peerdecl
//
//-------------------------------------------------------------------------
HRESULT
CAnchorClick::GetProperty_BSTR (IDispatch * pDisp, LPWSTR pchName, LPWSTR * pbstrRes)
{
HRESULT hr = S_OK;
VARIANT varRes;
if (!pbstrRes)
return E_POINTER;
*pbstrRes = NULL;
hr = GetProperty_Variant (pDisp, pchName, &varRes);
if (hr)
goto Cleanup;
if (VT_BSTR != V_VT(&varRes))
{
hr = E_UNEXPECTED;
goto Cleanup;
}
(*pbstrRes) = V_BSTR(&varRes);
Cleanup:
return hr;
}
// ========================================================================
// CEventSink::IDispatch
// ========================================================================
// The event sink's IDispatch interface is what gets called when events
// are fired.
//+------------------------------------------------------------------------
//
// Member: CAnchorClick::CEventSink::GetTypeInfoCount
// CAnchorClick::CEventSink::GetTypeInfo
// CAnchorClick::CEventSink::GetIDsOfNames
//
// Synopsis: We don't really need a nice IDispatch... this minimalist
// version does just plenty.
//
//-------------------------------------------------------------------------
STDMETHODIMP
CAnchorClick::CEventSink::GetTypeInfoCount(UINT* /*pctinfo*/)
{
return E_NOTIMPL;
}
STDMETHODIMP
CAnchorClick::CEventSink::GetTypeInfo(/* [in] */ UINT /*iTInfo*/,
/* [in] */ LCID /*lcid*/,
/* [out] */ ITypeInfo** /*ppTInfo*/)
{
return E_NOTIMPL;
}
STDMETHODIMP
CAnchorClick::CEventSink::GetIDsOfNames( REFIID riid,
OLECHAR** rgszNames,
UINT cNames,
LCID lcid,
DISPID* rgDispId)
{
return E_NOTIMPL;
}
//+------------------------------------------------------------------------
//
// Member: CAnchorClick::CEventSink::Invoke
//
// Synopsis: This gets called for all events on our object. (it was
// registered to do so in Init with attach_event.) It calls
// the appropriate parent functions to handle the events.
//
//-------------------------------------------------------------------------
STDMETHODIMP
CAnchorClick::CEventSink::Invoke( DISPID dispIdMember,
REFIID, LCID,
WORD wFlags,
DISPPARAMS* pDispParams,
VARIANT* pVarResult,
EXCEPINFO*,
UINT* puArgErr)
{
HRESULT hr = TRUE;
if (m_pParent && pDispParams && pDispParams->cArgs>=1)
{
if (pDispParams->rgvarg[0].vt == VT_DISPATCH)
{
IHTMLEventObj *pObj=NULL;
if (SUCCEEDED(pDispParams->rgvarg[0].pdispVal->QueryInterface(IID_IHTMLEventObj,
(void **)&pObj) && pObj))
{
BSTR bstrEvent=NULL;
pObj->get_type(&bstrEvent);
// user clicked one of our anchors
if (! StrCmpICW (bstrEvent, L"click"))
hr = m_pParent->ProcOnClick();
else if (! StrCmpICW (bstrEvent, L"ContextMenu"))
{
VARIANT vboolCancel;
vboolCancel.vt = VT_BOOL;
vboolCancel.boolVal = FALSE;
pObj->put_returnValue(vboolCancel);
hr = S_OK;
}
pObj->Release();
}
}
}
return hr;
}
//+------------------------------------------------------------------------
//
// Member: CAnchorClick::CEventSink
//
// Synopsis: This is used to allow communication between the parent class
// and the event sink class. The event sink will call the ProcOn*
// methods on the parent at the appropriate times.
//
//-------------------------------------------------------------------------
CAnchorClick::CEventSink::CEventSink (CAnchorClick * pParent)
{
m_pParent = pParent;
}
// ========================================================================
// CEventSink::IUnknown
// ========================================================================
// Vanilla IUnknown implementation for the event sink.
STDMETHODIMP
CAnchorClick::CEventSink::QueryInterface(REFIID riid, void ** ppUnk)
{
void * pUnk = NULL;
if (riid == IID_IDispatch)
pUnk = (IDispatch *) this;
if (riid == IID_IUnknown)
pUnk = (IUnknown *) this;
if (pUnk)
{
*ppUnk = pUnk;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG)
CAnchorClick::CEventSink::AddRef(void)
{
return ((IElementBehavior *)m_pParent)->AddRef();
}
STDMETHODIMP_(ULONG)
CAnchorClick::CEventSink::Release(void)
{
return ((IElementBehavior *)m_pParent)->Release();
}