forked from mirrors/gecko-dev
1134 lines
31 KiB
C++
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;
|
|
}
|