fune/embedding/browser/activex/src/plugin/XPConnect.cpp

1134 lines
31 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Adam Lock <adamlock@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "stdafx.h"
#ifdef XPCOM_GLUE
#include "nsXPCOMGlue.h"
#endif
#include "nsCOMPtr.h"
#include "nsIComponentManager.h"
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsIMozAxPlugin.h"
#include "nsIVariant.h"
#include "nsMemory.h"
#include "nsIDOMDocument.h"
#include "nsIDOMNode.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMElement.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMWindow.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIEventListenerManager.h"
#include "nsIScriptEventManager.h"
#include "jsapi.h"
#include "LegacyPlugin.h"
#include "XPConnect.h"
#ifdef XPC_IDISPATCH_SUPPORT
#include "nsIDOMWindowInternal.h"
#include "nsIDOMLocation.h"
#include "nsNetUtil.h"
#ifdef XPCOM_GLUE
#include "nsEmbedString.h"
#endif
#include "nsIURI.h"
#endif
///////////////////////////////////////////////////////////////////////////////
// nsScriptablePeer
nsScriptablePeer::nsScriptablePeer() :
mTearOff(new nsScriptablePeerTearOff(this))
{
NS_ASSERTION(mTearOff, "can't create tearoff");
MozAxPlugin::AddRef();
}
nsScriptablePeer::~nsScriptablePeer()
{
delete mTearOff;
MozAxPlugin::Release();
}
NS_IMPL_ADDREF(nsScriptablePeer)
NS_IMPL_RELEASE(nsScriptablePeer)
// Custom QueryInterface impl to deal with the IDispatch tearoff
NS_IMETHODIMP
nsScriptablePeer::QueryInterface(const nsIID & aIID, void **aInstancePtr)
{
NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!");
if (!aInstancePtr)
return NS_ERROR_NULL_POINTER;
*aInstancePtr = nsnull;
nsISupports* foundInterface = nsnull;
if (aIID.Equals(NS_GET_IID(nsISupports)))
foundInterface = static_cast<nsISupports *>(static_cast<nsIClassInfo *>(this));
else if (aIID.Equals(NS_GET_IID(nsIClassInfo)))
foundInterface = static_cast<nsIClassInfo*>(this);
else if (aIID.Equals(NS_GET_IID(nsIMozAxPlugin)))
foundInterface = static_cast<nsIMozAxPlugin*>(this);
else if (memcmp(&aIID, &__uuidof(IDispatch), sizeof(nsID)) == 0)
{
HRESULT hr = mTearOff->QueryInterface(__uuidof(IDispatch), aInstancePtr);
if (SUCCEEDED(hr)) return NS_OK;
return E_FAIL;
}
NS_IF_ADDREF(foundInterface);
*aInstancePtr = foundInterface;
return (*aInstancePtr) ? NS_OK : NS_NOINTERFACE;
}
HRESULT
nsScriptablePeer::GetIDispatch(IDispatch **pdisp)
{
if (pdisp == NULL)
{
return E_INVALIDARG;
}
*pdisp = NULL;
IUnknownPtr unk;
HRESULT hr = mPlugin->pControlSite->GetControlUnknown(&unk);
if (unk.GetInterfacePtr() == NULL)
{
return E_FAIL;
}
IDispatchPtr disp = unk;
if (disp.GetInterfacePtr() == NULL)
{
return E_FAIL;
}
*pdisp = disp.GetInterfacePtr();
(*pdisp)->AddRef();
return S_OK;
}
nsresult
nsScriptablePeer::HR2NS(HRESULT hr) const
{
switch (hr)
{
case S_OK:
return NS_OK;
case E_NOTIMPL:
return NS_ERROR_NOT_IMPLEMENTED;
case E_NOINTERFACE:
return NS_ERROR_NO_INTERFACE;
case E_INVALIDARG:
return NS_ERROR_INVALID_ARG;
case E_ABORT:
return NS_ERROR_ABORT;
case E_UNEXPECTED:
return NS_ERROR_UNEXPECTED;
case E_OUTOFMEMORY:
return NS_ERROR_OUT_OF_MEMORY;
case E_POINTER:
return NS_ERROR_INVALID_POINTER;
case E_FAIL:
default:
return NS_ERROR_FAILURE;
}
}
HRESULT
nsScriptablePeer::ConvertVariants(nsIVariant *aIn, VARIANT *aOut)
{
if (aIn == NULL || aOut == NULL)
{
return NS_ERROR_INVALID_ARG;
}
PRBool isWritable = PR_FALSE;
nsCOMPtr<nsIWritableVariant> writable = do_QueryInterface(aIn);
if (writable)
{
writable->GetWritable(&isWritable);
}
PRUint16 type;
nsresult rv = aIn->GetDataType(&type);
switch (type)
{
case nsIDataType::VTYPE_INT8:
{
PRUint8 value = 0;
rv = aIn->GetAsInt8(&value);
aOut->vt = VT_I1;
aOut->cVal = value;
}
break;
case nsIDataType::VTYPE_INT16:
{
PRInt16 value = 0;
rv = aIn->GetAsInt16(&value);
aOut->vt = VT_I2;
aOut->iVal = value;
}
break;
case nsIDataType::VTYPE_INT32:
{
PRInt32 value = 0;
rv = aIn->GetAsInt32(&value);
aOut->vt = VT_I4;
aOut->lVal = value;
}
break;
case nsIDataType::VTYPE_CHAR:
case nsIDataType::VTYPE_UINT8:
{
PRUint8 value = 0;
rv = aIn->GetAsInt8(&value);
aOut->vt = VT_UI1;
aOut->bVal = value;
}
break;
case nsIDataType::VTYPE_WCHAR:
case nsIDataType::VTYPE_UINT16:
{
PRUint16 value = 0;
rv = aIn->GetAsUint16(&value);
aOut->vt = VT_I2;
aOut->uiVal = value;
}
break;
case nsIDataType::VTYPE_UINT32:
{
PRUint32 value = 0;
rv = aIn->GetAsUint32(&value);
aOut->vt = VT_I4;
aOut->ulVal = value;
}
break;
case nsIDataType::VTYPE_FLOAT:
{
float value = 0;
rv = aIn->GetAsFloat(&value);
aOut->vt = VT_R4;
aOut->fltVal = value;
}
break;
case nsIDataType::VTYPE_DOUBLE:
{
double value = 0;
rv = aIn->GetAsDouble(&value);
aOut->vt = VT_R4;
aOut->dblVal = value;
}
break;
case nsIDataType::VTYPE_BOOL:
{
PRBool value = 0;
rv = aIn->GetAsBool(&value);
aOut->vt = VT_BOOL;
aOut->dblVal = value ? VARIANT_TRUE : VARIANT_FALSE;
}
break;
case nsIDataType::VTYPE_EMPTY:
VariantClear(aOut);
break;
case nsIDataType::VTYPE_STRING_SIZE_IS:
case nsIDataType::VTYPE_CHAR_STR:
{
nsCString value;
aIn->GetAsString(getter_Copies(value));
nsString valueWide;
NS_CStringToUTF16(value, NS_CSTRING_ENCODING_ASCII, valueWide);
aOut->vt = VT_BSTR;
aOut->bstrVal = SysAllocString(valueWide.get());
}
break;
case nsIDataType::VTYPE_WSTRING_SIZE_IS:
case nsIDataType::VTYPE_WCHAR_STR:
{
nsString value;
aIn->GetAsWString(getter_Copies(value));
aOut->vt = VT_BSTR;
aOut->bstrVal = SysAllocString(value.get());
}
break;
case nsIDataType::VTYPE_ASTRING:
{
nsAutoString value;
aIn->GetAsAString(value);
aOut->vt = VT_BSTR;
aOut->bstrVal = SysAllocString(value.get());
}
break;
case nsIDataType::VTYPE_DOMSTRING:
{
nsAutoString value;
aIn->GetAsAString(value);
aOut->vt = VT_BSTR;
aOut->bstrVal = SysAllocString(value.get());
}
break;
case nsIDataType::VTYPE_CSTRING:
{
nsCAutoString value;
aIn->GetAsACString(value);
nsAutoString valueWide;
NS_CStringToUTF16(value, NS_CSTRING_ENCODING_ASCII, valueWide);
aOut->vt = VT_BSTR;
aOut->bstrVal = SysAllocString(valueWide.get());
}
break;
case nsIDataType::VTYPE_UTF8STRING:
{
nsCAutoString value;
aIn->GetAsAUTF8String(value);
nsAutoString valueWide;
CopyUTF8toUTF16(value, valueWide);
aOut->vt = VT_BSTR;
aOut->bstrVal = SysAllocString(valueWide.get());
}
// Unsupported types
default:
case nsIDataType::VTYPE_INT64:
case nsIDataType::VTYPE_UINT64:
case nsIDataType::VTYPE_VOID:
case nsIDataType::VTYPE_ID:
case nsIDataType::VTYPE_INTERFACE:
case nsIDataType::VTYPE_INTERFACE_IS:
case nsIDataType::VTYPE_ARRAY:
case nsIDataType::VTYPE_EMPTY_ARRAY:
return E_INVALIDARG;
}
return S_OK;
}
HRESULT
nsScriptablePeer::ConvertVariants(VARIANT *aIn, nsIVariant **aOut)
{
if (aIn == NULL || aOut == NULL)
{
return NS_ERROR_INVALID_ARG;
}
*aOut = nsnull;
nsresult rv;
nsCOMPtr<nsIWritableVariant> v = do_CreateInstance("@mozilla.org/variant;1", &rv);
// NOTE: THIS IS AN UGLY BACKWARDS COMPATIBILITY HACK TO WORKAROUND
// XPCOM GLUE'S INABILITY TO FIND A CERTAIN ENTRY POINT IN MOZ1.0.x/NS7.0!
// DO NOT TAUNT THE HACK
if (NS_FAILED(rv))
{
// do_CreateInstance macro is broken so load the component manager by
// hand and get it to create the component.
HMODULE hlib = ::LoadLibrary("xpcom.dll");
if (hlib)
{
nsIComponentManager *pManager = nsnull; // A frozen interface, even in 1.0.x
typedef nsresult (PR_CALLBACK *Moz1XGetComponentManagerFunc)(nsIComponentManager* *result);
Moz1XGetComponentManagerFunc compMgr = (Moz1XGetComponentManagerFunc)
::GetProcAddress(hlib, "NS_GetComponentManager");
if (compMgr)
{
compMgr(&pManager);
if (pManager)
{
rv = pManager->CreateInstanceByContractID("@mozilla.org/variant;1",
nsnull, NS_GET_IID(nsIWritableVariant),
getter_AddRefs(v));
pManager->Release();
}
}
::FreeLibrary(hlib);
}
}
// END HACK
NS_ENSURE_SUCCESS(rv, rv);
switch (aIn->vt)
{
case VT_EMPTY:
v->SetAsEmpty();
break;
case VT_BSTR:
v->SetAsWString(aIn->bstrVal);
break;
case VT_I1:
v->SetAsInt8(aIn->cVal);
break;
case VT_I2:
v->SetAsInt16(aIn->iVal);
break;
case VT_I4:
v->SetAsInt32(aIn->lVal);
break;
case VT_UI1:
v->SetAsUint8(aIn->bVal);
break;
case VT_UI2:
v->SetAsUint16(aIn->uiVal);
break;
case VT_UI4:
v->SetAsUint32(aIn->ulVal);
break;
case VT_BOOL:
v->SetAsBool(aIn->boolVal == VARIANT_TRUE ? PR_TRUE : PR_FALSE);
break;
case VT_R4:
v->SetAsFloat(aIn->fltVal);
break;
case VT_R8:
v->SetAsDouble(aIn->dblVal);
break;
}
*aOut = v;
NS_ADDREF(*aOut);
return NS_OK;
}
NS_IMETHODIMP
nsScriptablePeer::InternalInvoke(const char *aMethod, unsigned int aNumArgs, nsIVariant *aArgs[])
{
HRESULT hr;
DISPID dispid;
IDispatchPtr disp;
if (FAILED(GetIDispatch(&disp)))
{
return NPERR_GENERIC_ERROR;
}
USES_CONVERSION;
OLECHAR FAR* szMember = A2OLE(aMethod);
hr = disp->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_USER_DEFAULT, &dispid);
if (FAILED(hr))
{
return NPERR_GENERIC_ERROR;
}
_variant_t *pArgs = NULL;
if (aNumArgs > 0)
{
pArgs = new _variant_t[aNumArgs];
if (pArgs == NULL)
{
return NS_ERROR_OUT_OF_MEMORY;
}
for (unsigned int i = 0; i < aNumArgs; i++)
{
hr = ConvertVariants(aArgs[i], &pArgs[i]);
if (FAILED(hr))
{
delete []pArgs;
return NS_ERROR_INVALID_ARG;
}
}
}
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
_variant_t vResult;
dispparams.cArgs = aNumArgs;
dispparams.rgvarg = pArgs;
hr = disp->Invoke(
dispid,
IID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_METHOD,
&dispparams, &vResult, NULL, NULL);
if (pArgs)
{
delete []pArgs;
}
if (FAILED(hr))
{
return NPERR_GENERIC_ERROR;
}
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////
// nsIMozAxPlugin
NS_IMETHODIMP
nsScriptablePeer::Invoke(const char *aMethod)
{
return InternalInvoke(aMethod, 0, NULL);
}
NS_IMETHODIMP
nsScriptablePeer::Invoke1(const char *aMethod, nsIVariant *a)
{
nsIVariant *args[1];
args[0] = a;
return InternalInvoke(aMethod, sizeof(args) / sizeof(args[0]), args);
}
NS_IMETHODIMP
nsScriptablePeer::Invoke2(const char *aMethod, nsIVariant *a, nsIVariant *b)
{
nsIVariant *args[2];
args[0] = a;
args[1] = b;
return InternalInvoke(aMethod, sizeof(args) / sizeof(args[0]), args);
}
NS_IMETHODIMP
nsScriptablePeer::Invoke3(const char *aMethod, nsIVariant *a, nsIVariant *b, nsIVariant *c)
{
nsIVariant *args[3];
args[0] = a;
args[1] = b;
args[2] = c;
return InternalInvoke(aMethod, sizeof(args) / sizeof(args[0]), args);
}
NS_IMETHODIMP
nsScriptablePeer::Invoke4(const char *aMethod, nsIVariant *a, nsIVariant *b, nsIVariant *c, nsIVariant *d)
{
nsIVariant *args[4];
args[0] = a;
args[1] = b;
args[2] = c;
args[3] = d;
return InternalInvoke(aMethod, sizeof(args) / sizeof(args[0]), args);
}
NS_IMETHODIMP
nsScriptablePeer::GetProperty(const char *propertyName, nsIVariant **_retval)
{
HRESULT hr;
DISPID dispid;
IDispatchPtr disp;
if (FAILED(GetIDispatch(&disp)))
{
return NPERR_GENERIC_ERROR;
}
USES_CONVERSION;
OLECHAR FAR* szMember = A2OLE(propertyName);
hr = disp->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_USER_DEFAULT, &dispid);
if (FAILED(hr))
{
return NPERR_GENERIC_ERROR;
}
_variant_t vResult;
DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
hr = disp->Invoke(
dispid,
IID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYGET,
&dispparamsNoArgs, &vResult, NULL, NULL);
if (FAILED(hr))
{
return NPERR_GENERIC_ERROR;
}
nsCOMPtr<nsIVariant> propertyValue;
ConvertVariants(&vResult, getter_AddRefs(propertyValue));
*_retval = propertyValue;
NS_IF_ADDREF(*_retval);
return NS_OK;
}
/* void setProperty (in string propertyName, in string propertyValue); */
NS_IMETHODIMP
nsScriptablePeer::SetProperty(const char *propertyName, nsIVariant *propertyValue)
{
HRESULT hr;
DISPID dispid;
IDispatchPtr disp;
if (FAILED(GetIDispatch(&disp)))
{
return NPERR_GENERIC_ERROR;
}
USES_CONVERSION;
OLECHAR FAR* szMember = A2OLE(propertyName);
hr = disp->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_USER_DEFAULT, &dispid);
if (FAILED(hr))
{
return NPERR_GENERIC_ERROR;
}
_variant_t v;
ConvertVariants(propertyValue, &v);
DISPID dispIdPut = DISPID_PROPERTYPUT;
DISPPARAMS functionArgs;
_variant_t vResult;
functionArgs.rgdispidNamedArgs = &dispIdPut;
functionArgs.rgvarg = &v;
functionArgs.cArgs = 1;
functionArgs.cNamedArgs = 1;
hr = disp->Invoke(
dispid,
IID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYPUT,
&functionArgs, &vResult, NULL, NULL);
if (FAILED(hr))
{
return NPERR_GENERIC_ERROR;
}
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////
#ifdef XPC_IDISPATCH_SUPPORT
HRESULT
nsEventSink::InternalInvoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
FUNCDESC *pFuncDesc = NULL;
HRESULT hr = S_OK;
CComBSTR bstrName;
// Must search and compare each member to the dispid...
if (m_spEventSinkTypeInfo)
{
HRESULT hr = S_OK;
TYPEATTR* pAttr;
hr = m_spEventSinkTypeInfo->GetTypeAttr(&pAttr);
if (pAttr)
{
int i;
for (i = 0; i < pAttr->cFuncs;i++)
{
hr = m_spEventSinkTypeInfo->GetFuncDesc(i, &pFuncDesc);
if (FAILED(hr))
return hr;
if (pFuncDesc->memid == dispIdMember)
{
UINT cNames = 0;
m_spEventSinkTypeInfo->GetNames(dispIdMember, &bstrName, 1, &cNames);
break;
}
m_spEventSinkTypeInfo->ReleaseFuncDesc(pFuncDesc);
pFuncDesc = NULL;
}
m_spEventSinkTypeInfo->ReleaseTypeAttr(pAttr);
}
}
if (!pFuncDesc)
{
// Return
return S_OK;
}
#ifdef DEBUG
{
// Dump out some info to look at
ATLTRACE(_T("Invoke(%d)\n"), (int) dispIdMember);
ATLTRACE(_T(" "));
/* Return code */
switch (pFuncDesc->elemdescFunc.tdesc.vt)
{
case VT_HRESULT: ATLTRACE(_T("HRESULT")); break;
case VT_VOID: ATLTRACE(_T("void")); break;
default: ATLTRACE(_T("void /* vt = %d */"), pFuncDesc->elemdescFunc.tdesc.vt); break;
}
/* Function name */
ATLTRACE(_T(" %S("), SUCCEEDED(hr) ? bstrName.m_str : L"?unknown?");
/* Parameters */
for (int i = 0; i < pFuncDesc->cParams; i++)
{
USHORT paramFlags = pFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags;
ATLTRACE("[");
BOOL addComma = FALSE;
if (paramFlags & PARAMFLAG_FIN)
{
ATLTRACE(_T("in")); addComma = TRUE;
}
if (paramFlags & PARAMFLAG_FOUT)
{
ATLTRACE(addComma ? _T(",out") : _T("out")); addComma = TRUE;
}
if (paramFlags & PARAMFLAG_FRETVAL)
{
ATLTRACE(addComma ? _T(",retval") : _T("retval")); addComma = TRUE;
}
ATLTRACE("] ");
VARTYPE vt = pFuncDesc->lprgelemdescParam[i].tdesc.vt;
switch (vt)
{
case VT_HRESULT: ATLTRACE(_T("HRESULT")); break;
case VT_VARIANT: ATLTRACE(_T("VARIANT")); break;
case VT_I2: ATLTRACE(_T("short")); break;
case VT_I4: ATLTRACE(_T("long")); break;
case VT_R8: ATLTRACE(_T("double")); break;
case VT_BOOL: ATLTRACE(_T("VARIANT_BOOL")); break;
case VT_BSTR: ATLTRACE(_T("BSTR")); break;
case VT_DISPATCH: ATLTRACE(_T("IDispatch *")); break;
case VT_UNKNOWN: ATLTRACE(_T("IUnknown *")); break;
case VT_USERDEFINED: ATLTRACE(_T("/* Userdefined */")); break;
case VT_PTR: ATLTRACE(_T("void *")); break;
case VT_VOID: ATLTRACE(_T("void")); break;
// More could be added...
default: ATLTRACE(_T("/* vt = %d */"), vt); break;
}
if (i + 1 < pFuncDesc->cParams)
{
ATLTRACE(_T(", "));
}
}
ATLTRACE(_T(");\n"));
}
#endif
m_spEventSinkTypeInfo->ReleaseFuncDesc(pFuncDesc);
pFuncDesc = NULL;
nsCOMPtr<nsIDOMElement> element;
NPN_GetValue(mPlugin->pPluginInstance, NPNVDOMElement,
static_cast<nsIDOMElement **>(getter_AddRefs(element)));
if (!element)
{
NS_ERROR("can't get the object element");
return S_OK;
}
nsAutoString id;
if (NS_FAILED(element->GetAttribute(NS_LITERAL_STRING("id"), id)) ||
id.IsEmpty())
{
// Object has no name so it can't fire events
return S_OK;
}
nsDependentString eventName(bstrName.m_str);
// Fire the script event handler...
nsCOMPtr<nsIDOMWindow> window;
NPN_GetValue(mPlugin->pPluginInstance, NPNVDOMWindow,
static_cast<nsIDOMWindow **>(getter_AddRefs(window)));
nsCOMPtr<nsIScriptEventManager> eventManager(do_GetInterface(window));
if (!eventManager) return S_OK;
nsCOMPtr<nsISupports> handler;
eventManager->FindEventHandler(id, eventName, pDispParams->cArgs, getter_AddRefs(handler));
if (!handler)
{
return S_OK;
}
// Create a list of arguments to pass along
//
// This array is created on the stack if the number of arguments
// less than kMaxArgsOnStack. Otherwise, the array is heap
// allocated.
//
const int kMaxArgsOnStack = 10;
PRUint32 argc = pDispParams->cArgs;
jsval *args = nsnull;
jsval stackArgs[kMaxArgsOnStack];
// Heap allocate the jsval array if it is too big to fit on
// the stack (ie. more than kMaxArgsOnStack arguments)
if (argc > kMaxArgsOnStack)
{
args = new jsval[argc];
if (!args) return S_OK;
}
else if (argc)
{
// Use the jsval array on the stack...
args = stackArgs;
}
if (argc)
{
nsCOMPtr<nsIDispatchSupport> disp(do_GetService("@mozilla.org/nsdispatchsupport;1"));
for (UINT i = 0; i < argc; i++)
{
// Arguments are listed backwards, intentionally, in rgvarg
disp->COMVariant2JSVal(&pDispParams->rgvarg[argc - 1 - i], &args[i]);
}
}
// Fire the Event.
eventManager->InvokeEventHandler(handler, element, args, argc);
// Free the jsvals if they were heap allocated...
if (args != stackArgs)
{
delete [] args;
}
// TODO Turn js objects for out params back into VARIANTS
// TODO Turn js return code into VARIANT
// TODO handle js exception and fill in exception info (do we care?)
if (pExcepInfo)
{
pExcepInfo->wCode = 0;
}
return S_OK;
}
#endif
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// nsScriptablePeerTearOff
nsScriptablePeerTearOff::nsScriptablePeerTearOff(nsScriptablePeer *pOwner) :
mOwner(pOwner)
{
NS_ASSERTION(mOwner, "no owner");
}
HRESULT STDMETHODCALLTYPE nsScriptablePeerTearOff::QueryInterface(REFIID riid, void **ppvObject)
{
if (::IsEqualIID(riid, _uuidof(IDispatch)))
{
*ppvObject = dynamic_cast<IDispatch *>(this);
mOwner->AddRef();
return NS_OK;
}
nsID iid;
memcpy(&iid, &riid, sizeof(nsID));
return mOwner->QueryInterface(iid, ppvObject);
}
ULONG STDMETHODCALLTYPE nsScriptablePeerTearOff::AddRef()
{
return mOwner->AddRef();
}
ULONG STDMETHODCALLTYPE nsScriptablePeerTearOff::Release()
{
return mOwner->Release();
}
// IDispatch
HRESULT STDMETHODCALLTYPE nsScriptablePeerTearOff::GetTypeInfoCount(UINT __RPC_FAR *pctinfo)
{
CComPtr<IDispatch> disp;
if (FAILED(mOwner->GetIDispatch(&disp)))
{
return E_UNEXPECTED;
}
return disp->GetTypeInfoCount(pctinfo);
}
HRESULT STDMETHODCALLTYPE nsScriptablePeerTearOff::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo)
{
CComPtr<IDispatch> disp;
if (FAILED(mOwner->GetIDispatch(&disp)))
{
return E_UNEXPECTED;
}
return disp->GetTypeInfo(iTInfo, lcid, ppTInfo);
}
HRESULT STDMETHODCALLTYPE nsScriptablePeerTearOff::GetIDsOfNames(REFIID riid, LPOLESTR __RPC_FAR *rgszNames, UINT cNames, LCID lcid, DISPID __RPC_FAR *rgDispId)
{
CComPtr<IDispatch> disp;
if (FAILED(mOwner->GetIDispatch(&disp)))
{
return E_UNEXPECTED;
}
return disp->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispId);
}
HRESULT STDMETHODCALLTYPE nsScriptablePeerTearOff::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS __RPC_FAR *pDispParams, VARIANT __RPC_FAR *pVarResult, EXCEPINFO __RPC_FAR *pExcepInfo, UINT __RPC_FAR *puArgErr)
{
CComPtr<IDispatch> disp;
if (FAILED(mOwner->GetIDispatch(&disp)))
{
return E_UNEXPECTED;
}
return disp->Invoke(dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Some public methods
static PRUint32 gInstances = 0;
void MozAxPlugin::AddRef()
{
if (gInstances == 0)
{
#ifdef XPCOM_GLUE
XPCOMGlueStartup(nsnull);
#endif
MozAxPlugin::PrefGetHostingFlags(); // Initial call to set it up
}
gInstances++;
}
void MozAxPlugin::Release()
{
if (--gInstances == 0)
{
#ifdef XPC_IDISPATCH_SUPPORT
MozAxPlugin::ReleasePrefObserver();
#endif
#ifdef XPCOM_GLUE
XPCOMGlueShutdown();
#endif
}
}
#ifdef XPC_IDISPATCH_SUPPORT
nsresult MozAxPlugin::GetCurrentLocation(NPP instance, nsIURI **aLocation)
{
NS_ENSURE_ARG_POINTER(aLocation);
*aLocation = nsnull;
nsCOMPtr<nsIDOMWindow> domWindow;
NPN_GetValue(instance, NPNVDOMWindow, (void *) &domWindow);
if (!domWindow)
{
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMWindowInternal> windowInternal = do_QueryInterface(domWindow);
if (!windowInternal)
{
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMLocation> location;
#ifdef XPCOM_GLUE
nsEmbedString href;
#else
nsAutoString href;
#endif
windowInternal->GetLocation(getter_AddRefs(location));
if (!location ||
NS_FAILED(location->GetHref(href)))
{
return NS_ERROR_FAILURE;
}
return NS_NewURI(aLocation, href);
}
#endif
CLSID MozAxPlugin::GetCLSIDForType(const char *mimeType)
{
if (mimeType == NULL)
{
return CLSID_NULL;
}
// Read the registry to see if there is a CLSID for an object to be associated with
// this MIME type.
USES_CONVERSION;
CRegKey keyMimeDB;
if (keyMimeDB.Open(HKEY_CLASSES_ROOT, _T("MIME\\Database\\Content Type"), KEY_READ) == ERROR_SUCCESS)
{
CRegKey keyMimeType;
if (keyMimeType.Open(keyMimeDB, A2CT(mimeType), KEY_READ) == ERROR_SUCCESS)
{
USES_CONVERSION;
TCHAR szGUID[64];
ULONG nCount = (sizeof(szGUID) / sizeof(szGUID[0])) - 1;
GUID guidValue = GUID_NULL;
if (keyMimeType.QueryValue(szGUID, _T("CLSID"), &nCount) == ERROR_SUCCESS &&
SUCCEEDED(::CLSIDFromString(T2OLE(szGUID), &guidValue)))
{
return guidValue;
}
}
}
return CLSID_NULL;
}
nsScriptablePeer *
MozAxPlugin::GetPeerForCLSID(const CLSID &clsid)
{
return new nsScriptablePeer();
}
void
MozAxPlugin::GetIIDForCLSID(const CLSID &clsid, nsIID &iid)
{
#ifdef XPC_IDISPATCH_SUPPORT
memcpy(&iid, &__uuidof(IDispatch), sizeof(iid));
#else
iid = NS_GET_IID(nsIMozAxPlugin);
#endif
}
// Called by NPP_GetValue to provide the scripting values
NPError
MozAxPlugin::GetValue(NPP instance, NPPVariable variable, void *value)
{
if (instance == NULL)
{
return NPERR_INVALID_INSTANCE_ERROR;
}
PluginInstanceData *pData = (PluginInstanceData *) instance->pdata;
if (!pData ||
!pData->pControlSite ||
!pData->pControlSite->IsObjectValid())
{
return NPERR_GENERIC_ERROR;
}
// Test if the object is allowed to be scripted
#ifdef XPC_IDISPATCH_SUPPORT
PRUint32 hostingFlags = MozAxPlugin::PrefGetHostingFlags();
if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_SAFE_OBJECTS &&
!(hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_ALL_OBJECTS))
{
// Ensure the object is safe for scripting on the specified interface
nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID);
if (!dispSupport) return NPERR_GENERIC_ERROR;
PRBool isScriptable = PR_FALSE;
// Test if the object says its safe for scripting on IDispatch
nsIID iid;
memcpy(&iid, &__uuidof(IDispatch), sizeof(iid));
CComPtr<IUnknown> controlUnk;
pData->pControlSite->GetControlUnknown(&controlUnk);
dispSupport->IsObjectSafeForScripting(reinterpret_cast<void *>(controlUnk.p), iid, &isScriptable);
// Test if the class id says safe for scripting
if (!isScriptable)
{
PRBool classExists = PR_FALSE;
nsCID cid;
memcpy(&cid, &pData->clsid, sizeof(cid));
dispSupport->IsClassMarkedSafeForScripting(cid, &classExists, &isScriptable);
}
if (!isScriptable)
{
return NPERR_GENERIC_ERROR;
}
}
else if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_ALL_OBJECTS)
{
// Drop through since all objects are scriptable
}
else
{
return NPERR_GENERIC_ERROR;
}
#else
// Object *must* be safe
if (!pData->pControlSite->IsObjectSafeForScripting(__uuidof(IDispatch)))
{
return NPERR_GENERIC_ERROR;
}
#endif
// Happy happy fun fun - redefine some NPPVariable values that we might
// be asked for but not defined by every PluginSDK
const int kVarScriptableInstance = 10; // NPPVpluginScriptableInstance
const int kVarScriptableIID = 11; // NPPVpluginScriptableIID
if (variable == kVarScriptableInstance)
{
if (!pData->pScriptingPeer)
{
nsScriptablePeer *peer = MozAxPlugin::GetPeerForCLSID(pData->clsid);
if (peer)
{
peer->AddRef();
pData->pScriptingPeer = (nsIMozAxPlugin *) peer;
peer->mPlugin = pData;
}
}
if (pData->pScriptingPeer)
{
pData->pScriptingPeer->AddRef();
*((nsISupports **) value)= pData->pScriptingPeer;
return NPERR_NO_ERROR;
}
}
else if (variable == kVarScriptableIID)
{
nsIID *piid = (nsIID *) NPN_MemAlloc(sizeof(nsIID));
GetIIDForCLSID(pData->clsid, *piid);
*((nsIID **) value) = piid;
return NPERR_NO_ERROR;
}
return NPERR_GENERIC_ERROR;
}