/* -*- 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 * * 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(static_cast(this)); else if (aIID.Equals(NS_GET_IID(nsIClassInfo))) foundInterface = static_cast(this); else if (aIID.Equals(NS_GET_IID(nsIMozAxPlugin))) foundInterface = static_cast(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 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 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 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 element; NPN_GetValue(mPlugin->pPluginInstance, NPNVDOMElement, static_cast(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 window; NPN_GetValue(mPlugin->pPluginInstance, NPNVDOMWindow, static_cast(getter_AddRefs(window))); nsCOMPtr eventManager(do_GetInterface(window)); if (!eventManager) return S_OK; nsCOMPtr 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 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(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 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 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 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 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 domWindow; NPN_GetValue(instance, NPNVDOMWindow, (void *) &domWindow); if (!domWindow) { return NS_ERROR_FAILURE; } nsCOMPtr windowInternal = do_QueryInterface(domWindow); if (!windowInternal) { return NS_ERROR_FAILURE; } nsCOMPtr 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 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 controlUnk; pData->pControlSite->GetControlUnknown(&controlUnk); dispSupport->IsObjectSafeForScripting(reinterpret_cast(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; }