Back to index

lightning-sunbird  0.9+nobinonly
XPConnect.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Adam Lock <adamlock@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #include "stdafx.h"
00039 
00040 #ifdef XPCOM_GLUE
00041 #include "nsXPCOMGlue.h"
00042 #endif
00043 
00044 #include "nsCOMPtr.h"
00045 #include "nsComponentManagerUtils.h"
00046 #include "nsServiceManagerUtils.h"
00047 
00048 #include "nsIMozAxPlugin.h"
00049 #include "nsIClassInfo.h"
00050 #include "nsIVariant.h"
00051 #include "nsMemory.h"
00052 
00053 #include "nsIAtom.h"
00054 
00055 #include "nsIDOMDocument.h"
00056 #include "nsIDOMNode.h"
00057 #include "nsIDOMNodeList.h"
00058 #include "nsIDOMElement.h"
00059 #include "nsIDOMEventReceiver.h"
00060 #include "nsIDOMWindow.h"
00061 
00062 #include "nsIInterfaceRequestorUtils.h"
00063 #include "nsIEventListenerManager.h"
00064 
00065 #include "nsIScriptEventManager.h"
00066 #include "jsapi.h"
00067 
00068 #include "LegacyPlugin.h"
00069 #include "XPConnect.h"
00070 
00071 #ifdef XPC_IDISPATCH_SUPPORT
00072 #include "nsIDOMWindowInternal.h"
00073 #include "nsIDOMLocation.h"
00074 #include "nsNetUtil.h"
00075 #ifdef XPCOM_GLUE
00076 #include "nsEmbedString.h"
00077 #endif
00078 #include "nsIURI.h"
00079 #endif
00080 
00081 
00083 // nsScriptablePeer
00084 
00085 nsScriptablePeer::nsScriptablePeer() :
00086     mTearOff(new nsScriptablePeerTearOff(this))
00087 {
00088     NS_ASSERTION(mTearOff, "can't create tearoff");
00089     MozAxPlugin::AddRef();
00090 }
00091 
00092 nsScriptablePeer::~nsScriptablePeer()
00093 {
00094     delete mTearOff;
00095     MozAxPlugin::Release();
00096 }
00097 
00098 NS_IMPL_ADDREF(nsScriptablePeer)
00099 NS_IMPL_RELEASE(nsScriptablePeer)
00100 
00101 // Custom QueryInterface impl to deal with the IDispatch tearoff
00102 NS_IMETHODIMP
00103 nsScriptablePeer::QueryInterface(const nsIID & aIID, void **aInstancePtr)
00104 {
00105     NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!");
00106     if (!aInstancePtr)
00107         return NS_ERROR_NULL_POINTER;
00108     *aInstancePtr = nsnull;
00109 
00110     nsISupports* foundInterface = nsnull;
00111     if (aIID.Equals(NS_GET_IID(nsISupports)))
00112         foundInterface = NS_STATIC_CAST(nsISupports *, NS_STATIC_CAST(nsIClassInfo *, this));
00113     else if (aIID.Equals(NS_GET_IID(nsIClassInfo)))
00114         foundInterface = NS_STATIC_CAST(nsIClassInfo*, this);
00115     else if (aIID.Equals(NS_GET_IID(nsIMozAxPlugin)))
00116         foundInterface = NS_STATIC_CAST(nsIMozAxPlugin*, this);
00117     else if (memcmp(&aIID, &__uuidof(IDispatch), sizeof(nsID)) == 0)
00118     {
00119         HRESULT hr = mTearOff->QueryInterface(__uuidof(IDispatch), aInstancePtr);
00120         if (SUCCEEDED(hr)) return NS_OK;
00121         return E_FAIL;
00122     }
00123 
00124     NS_IF_ADDREF(foundInterface);
00125     *aInstancePtr = foundInterface;
00126     return (*aInstancePtr) ? NS_OK : NS_NOINTERFACE;
00127 }
00128 
00129 HRESULT
00130 nsScriptablePeer::GetIDispatch(IDispatch **pdisp)
00131 {
00132     if (pdisp == NULL)
00133     {
00134         return E_INVALIDARG;
00135     }
00136     *pdisp = NULL;
00137 
00138     IUnknownPtr unk;
00139     HRESULT hr = mPlugin->pControlSite->GetControlUnknown(&unk);
00140     if (unk.GetInterfacePtr() == NULL)
00141     {
00142               return E_FAIL; 
00143        }
00144 
00145     IDispatchPtr disp = unk;
00146     if (disp.GetInterfacePtr() == NULL)
00147     { 
00148         return E_FAIL; 
00149     }
00150 
00151     *pdisp = disp.GetInterfacePtr();
00152     (*pdisp)->AddRef();
00153 
00154     return S_OK;
00155 }
00156 
00157 nsresult
00158 nsScriptablePeer::HR2NS(HRESULT hr) const
00159 {
00160     switch (hr)
00161     {
00162     case S_OK:
00163         return NS_OK;
00164     case E_NOTIMPL:
00165         return NS_ERROR_NOT_IMPLEMENTED;
00166     case E_NOINTERFACE:
00167         return NS_ERROR_NO_INTERFACE;
00168     case E_INVALIDARG:
00169         return NS_ERROR_INVALID_ARG;
00170     case E_ABORT:
00171         return NS_ERROR_ABORT;
00172     case E_UNEXPECTED:
00173         return NS_ERROR_UNEXPECTED;
00174     case E_OUTOFMEMORY:
00175         return NS_ERROR_OUT_OF_MEMORY;
00176     case E_POINTER:
00177         return NS_ERROR_INVALID_POINTER;
00178     case E_FAIL:
00179     default:
00180         return NS_ERROR_FAILURE;
00181     }
00182 }
00183 
00184 HRESULT
00185 nsScriptablePeer::ConvertVariants(nsIVariant *aIn, VARIANT *aOut)
00186 {
00187     if (aIn == NULL || aOut == NULL)
00188     {
00189         return NS_ERROR_INVALID_ARG;
00190     }
00191 
00192     PRBool isWritable = PR_FALSE;
00193     nsCOMPtr<nsIWritableVariant> writable = do_QueryInterface(aIn);
00194     if (writable)
00195     {
00196         writable->GetWritable(&isWritable);
00197     }
00198 
00199     PRUint16 type;
00200     nsresult rv = aIn->GetDataType(&type);
00201     switch (type)
00202     {
00203     case nsIDataType::VTYPE_INT8:
00204         {
00205             PRUint8 value = 0;
00206             rv = aIn->GetAsInt8(&value);
00207             aOut->vt = VT_I1;
00208             aOut->cVal = value;
00209         }
00210         break;
00211     case nsIDataType::VTYPE_INT16:
00212         {
00213             PRInt16 value = 0;
00214             rv = aIn->GetAsInt16(&value);
00215             aOut->vt = VT_I2;
00216             aOut->iVal = value;
00217         }
00218         break;
00219     case nsIDataType::VTYPE_INT32:
00220         {
00221             PRInt32 value = 0;
00222             rv = aIn->GetAsInt32(&value);
00223             aOut->vt = VT_I4;
00224             aOut->lVal = value;
00225         }
00226         break;
00227     case nsIDataType::VTYPE_CHAR:
00228     case nsIDataType::VTYPE_UINT8:
00229         {
00230             PRUint8 value = 0;
00231             rv = aIn->GetAsInt8(&value);
00232             aOut->vt = VT_UI1;
00233             aOut->bVal = value;
00234         }
00235         break;
00236     case nsIDataType::VTYPE_WCHAR:
00237     case nsIDataType::VTYPE_UINT16:
00238         {
00239             PRUint16 value = 0;
00240             rv = aIn->GetAsUint16(&value);
00241             aOut->vt = VT_I2;
00242             aOut->uiVal = value;
00243         }
00244         break;
00245     case nsIDataType::VTYPE_UINT32:
00246         {
00247             PRUint32 value = 0;
00248             rv = aIn->GetAsUint32(&value);
00249             aOut->vt = VT_I4;
00250             aOut->ulVal = value;
00251         }
00252         break;
00253     case nsIDataType::VTYPE_FLOAT:
00254         {
00255             float value = 0;
00256             rv = aIn->GetAsFloat(&value);
00257             aOut->vt = VT_R4;
00258             aOut->fltVal = value;
00259         }
00260         break;
00261     case nsIDataType::VTYPE_DOUBLE:
00262         {
00263             double value = 0;
00264             rv = aIn->GetAsDouble(&value);
00265             aOut->vt = VT_R4;
00266             aOut->dblVal = value;
00267         }
00268         break;
00269     case nsIDataType::VTYPE_BOOL:
00270         {
00271             PRBool value = 0;
00272             rv = aIn->GetAsBool(&value);
00273             aOut->vt = VT_BOOL;
00274             aOut->dblVal = value ? VARIANT_TRUE : VARIANT_FALSE;
00275         }
00276         break;
00277     case nsIDataType::VTYPE_EMPTY:
00278         VariantClear(aOut);
00279         break;
00280 
00281     case nsIDataType::VTYPE_STRING_SIZE_IS:
00282     case nsIDataType::VTYPE_CHAR_STR:
00283         {
00284             nsXPIDLCString value;
00285             aIn->GetAsString(getter_Copies(value));
00286             nsAutoString valueWide; valueWide.AssignWithConversion(value);
00287             aOut->vt = VT_BSTR;
00288             aOut->bstrVal = SysAllocString(valueWide.get());
00289         }
00290         break;
00291     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
00292     case nsIDataType::VTYPE_WCHAR_STR:
00293         {
00294             nsXPIDLString value;
00295             aIn->GetAsWString(getter_Copies(value));
00296             aOut->vt = VT_BSTR;
00297             aOut->bstrVal = SysAllocString(value.get());
00298         }
00299         break;
00300 
00301     case nsIDataType::VTYPE_ASTRING:
00302         {
00303             nsAutoString value;
00304             aIn->GetAsAString(value);
00305             aOut->vt = VT_BSTR;
00306             aOut->bstrVal = SysAllocString(value.get());
00307         }
00308         break;
00309 
00310     case nsIDataType::VTYPE_DOMSTRING:
00311         {
00312             nsAutoString value;
00313             aIn->GetAsAString(value);
00314             aOut->vt = VT_BSTR;
00315             aOut->bstrVal = SysAllocString(value.get());
00316         }
00317         break;
00318 
00319     case nsIDataType::VTYPE_CSTRING:
00320         {
00321             nsCAutoString value;
00322             aIn->GetAsACString(value);
00323             nsAutoString valueWide; valueWide.AssignWithConversion(value.get());
00324             aOut->vt = VT_BSTR;
00325             aOut->bstrVal = SysAllocString(valueWide.get());
00326         }
00327         break;
00328     case nsIDataType::VTYPE_UTF8STRING:
00329         {
00330             nsCAutoString value;
00331             aIn->GetAsAUTF8String(value);
00332             nsAutoString valueWide;
00333             CopyUTF8toUTF16(value, valueWide);
00334             aOut->vt = VT_BSTR;
00335             aOut->bstrVal = SysAllocString(valueWide.get());
00336         }
00337 
00338     // Unsupported types
00339     default:
00340     case nsIDataType::VTYPE_INT64:
00341     case nsIDataType::VTYPE_UINT64:
00342     case nsIDataType::VTYPE_VOID:
00343     case nsIDataType::VTYPE_ID:
00344     case nsIDataType::VTYPE_INTERFACE:
00345     case nsIDataType::VTYPE_INTERFACE_IS:
00346     case nsIDataType::VTYPE_ARRAY:
00347     case nsIDataType::VTYPE_EMPTY_ARRAY:
00348         return E_INVALIDARG;
00349     }
00350 
00351     return S_OK;
00352 }
00353 
00354 
00355 HRESULT
00356 nsScriptablePeer::ConvertVariants(VARIANT *aIn, nsIVariant **aOut)
00357 {
00358     if (aIn == NULL || aOut == NULL)
00359     {
00360         return NS_ERROR_INVALID_ARG;
00361     }
00362 
00363     *aOut = nsnull;
00364 
00365     nsresult rv;
00366     nsCOMPtr<nsIWritableVariant> v = do_CreateInstance("@mozilla.org/variant;1", &rv);
00367 
00368     // NOTE: THIS IS AN UGLY BACKWARDS COMPATIBILITY HACK TO WORKAROUND
00369     // XPCOM GLUE'S INABILITY TO FIND A CERTAIN ENTRY POINT IN MOZ1.0.x/NS7.0!
00370     // DO NOT TAUNT THE HACK
00371     if (NS_FAILED(rv))
00372     {
00373         // do_CreateInstance macro is broken so load the component manager by
00374         // hand and get it to create the component.
00375         HMODULE hlib = ::LoadLibrary("xpcom.dll");
00376         if (hlib)
00377         {
00378             nsIComponentManager *pManager = nsnull; // A frozen interface, even in 1.0.x
00379             typedef nsresult (PR_CALLBACK *Moz1XGetComponentManagerFunc)(nsIComponentManager* *result);
00380             Moz1XGetComponentManagerFunc compMgr = (Moz1XGetComponentManagerFunc)
00381                 ::GetProcAddress(hlib, "NS_GetComponentManager");
00382             if (compMgr)
00383             {
00384                 compMgr(&pManager);
00385                 if (pManager)
00386                 {
00387                     rv = pManager->CreateInstanceByContractID("@mozilla.org/variant;1",
00388                         nsnull, NS_GET_IID(nsIWritableVariant),
00389                         getter_AddRefs(v));
00390                     pManager->Release();
00391                 }
00392             }
00393             ::FreeLibrary(hlib);
00394         }
00395     }
00396     // END HACK
00397     NS_ENSURE_SUCCESS(rv, rv);
00398 
00399     switch (aIn->vt)
00400     {
00401     case VT_EMPTY:
00402         v->SetAsEmpty();
00403         break;
00404     case VT_BSTR:
00405         v->SetAsWString(aIn->bstrVal);
00406         break;
00407     case VT_I1:
00408         v->SetAsInt8(aIn->cVal);
00409         break;
00410     case VT_I2:
00411         v->SetAsInt16(aIn->iVal);
00412         break;
00413     case VT_I4:
00414         v->SetAsInt32(aIn->lVal);
00415         break;
00416     case VT_UI1:
00417         v->SetAsUint8(aIn->bVal);
00418         break;
00419     case VT_UI2:
00420         v->SetAsUint16(aIn->uiVal);
00421         break;
00422     case VT_UI4:
00423         v->SetAsUint32(aIn->ulVal);
00424         break;
00425     case VT_BOOL:
00426         v->SetAsBool(aIn->boolVal == VARIANT_TRUE ? PR_TRUE : PR_FALSE);
00427         break;
00428     case VT_R4:
00429         v->SetAsFloat(aIn->fltVal);
00430         break;
00431     case VT_R8:
00432         v->SetAsDouble(aIn->dblVal);
00433         break;
00434     }
00435 
00436     *aOut = v;
00437     NS_ADDREF(*aOut);
00438 
00439     return NS_OK;
00440 } 
00441 
00442 NS_IMETHODIMP
00443 nsScriptablePeer::InternalInvoke(const char *aMethod, unsigned int aNumArgs, nsIVariant *aArgs[])
00444 {
00445     HRESULT hr;
00446     DISPID dispid;
00447 
00448     IDispatchPtr disp;
00449     if (FAILED(GetIDispatch(&disp)))
00450     {
00451         return NPERR_GENERIC_ERROR; 
00452     }
00453 
00454     USES_CONVERSION;
00455     OLECHAR FAR* szMember = A2OLE(aMethod);
00456     hr = disp->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_USER_DEFAULT, &dispid);
00457     if (FAILED(hr))
00458     { 
00459         return NPERR_GENERIC_ERROR; 
00460     }
00461     
00462     _variant_t *pArgs = NULL;
00463     if (aNumArgs > 0)
00464     {
00465         pArgs = new _variant_t[aNumArgs];
00466         if (pArgs == NULL)
00467         {
00468             return NS_ERROR_OUT_OF_MEMORY;
00469         }
00470         for (unsigned int i = 0; i < aNumArgs; i++)
00471         {
00472             hr = ConvertVariants(aArgs[i], &pArgs[i]);
00473             if (FAILED(hr))
00474             {
00475                 delete []pArgs;
00476                 return NS_ERROR_INVALID_ARG;
00477             }
00478         }
00479     }
00480 
00481     DISPPARAMS dispparams = {NULL, NULL, 0, 0};
00482     _variant_t vResult;
00483 
00484     dispparams.cArgs = aNumArgs;
00485     dispparams.rgvarg = pArgs;
00486 
00487     hr = disp->Invoke(
00488         dispid,
00489         IID_NULL,
00490         LOCALE_USER_DEFAULT,
00491         DISPATCH_METHOD,
00492         &dispparams, &vResult, NULL, NULL);
00493 
00494     if (pArgs)
00495     {
00496         delete []pArgs;
00497     }
00498 
00499     if (FAILED(hr))
00500     { 
00501         return NPERR_GENERIC_ERROR; 
00502     }
00503 
00504     return NS_OK;
00505 }
00506 
00508 // nsIMozAxPlugin
00509 
00510 NS_IMETHODIMP 
00511 nsScriptablePeer::Invoke(const char *aMethod)
00512 {
00513     return InternalInvoke(aMethod, 0, NULL);
00514 }
00515 
00516 NS_IMETHODIMP 
00517 nsScriptablePeer::Invoke1(const char *aMethod, nsIVariant *a)
00518 {
00519     nsIVariant *args[1];
00520     args[0] = a;
00521     return InternalInvoke(aMethod, sizeof(args) / sizeof(args[0]), args);
00522 }
00523 
00524 NS_IMETHODIMP 
00525 nsScriptablePeer::Invoke2(const char *aMethod, nsIVariant *a, nsIVariant *b)
00526 {
00527     nsIVariant *args[2];
00528     args[0] = a;
00529     args[1] = b;
00530     return InternalInvoke(aMethod, sizeof(args) / sizeof(args[0]), args);
00531 }
00532 
00533 NS_IMETHODIMP 
00534 nsScriptablePeer::Invoke3(const char *aMethod, nsIVariant *a, nsIVariant *b, nsIVariant *c)
00535 {
00536     nsIVariant *args[3];
00537     args[0] = a;
00538     args[1] = b;
00539     args[2] = c;
00540     return InternalInvoke(aMethod, sizeof(args) / sizeof(args[0]), args);
00541 }
00542 
00543 NS_IMETHODIMP 
00544 nsScriptablePeer::Invoke4(const char *aMethod, nsIVariant *a, nsIVariant *b, nsIVariant *c, nsIVariant *d)
00545 {
00546     nsIVariant *args[4];
00547     args[0] = a;
00548     args[1] = b;
00549     args[2] = c;
00550     args[3] = d;
00551     return InternalInvoke(aMethod, sizeof(args) / sizeof(args[0]), args);
00552 }
00553 
00554 NS_IMETHODIMP 
00555 nsScriptablePeer::GetProperty(const char *propertyName, nsIVariant **_retval)
00556 {
00557     HRESULT hr;
00558     DISPID dispid;
00559     IDispatchPtr disp;
00560     if (FAILED(GetIDispatch(&disp)))
00561     {
00562         return NPERR_GENERIC_ERROR; 
00563     }
00564     USES_CONVERSION;
00565     OLECHAR FAR* szMember = A2OLE(propertyName);
00566     hr = disp->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_USER_DEFAULT, &dispid);
00567     if (FAILED(hr))
00568     { 
00569         return NPERR_GENERIC_ERROR;
00570     }
00571 
00572     _variant_t vResult;
00573     
00574     DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
00575     hr = disp->Invoke(
00576         dispid,
00577         IID_NULL,
00578         LOCALE_USER_DEFAULT,
00579         DISPATCH_PROPERTYGET,
00580         &dispparamsNoArgs, &vResult, NULL, NULL);
00581     
00582     if (FAILED(hr))
00583     { 
00584         return NPERR_GENERIC_ERROR;
00585     }
00586 
00587     nsCOMPtr<nsIVariant> propertyValue;
00588     ConvertVariants(&vResult, getter_AddRefs(propertyValue));
00589     *_retval = propertyValue;
00590     NS_IF_ADDREF(*_retval);
00591 
00592     return NS_OK;
00593 }
00594 
00595 /* void setProperty (in string propertyName, in string propertyValue); */
00596 NS_IMETHODIMP
00597 nsScriptablePeer::SetProperty(const char *propertyName, nsIVariant *propertyValue)
00598 {
00599     HRESULT hr;
00600     DISPID dispid;
00601     IDispatchPtr disp;
00602     if (FAILED(GetIDispatch(&disp)))
00603     {
00604         return NPERR_GENERIC_ERROR; 
00605     }
00606     USES_CONVERSION;
00607     OLECHAR FAR* szMember = A2OLE(propertyName);
00608     hr = disp->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_USER_DEFAULT, &dispid);
00609     if (FAILED(hr))
00610     { 
00611         return NPERR_GENERIC_ERROR;
00612     }
00613 
00614     _variant_t v;
00615     ConvertVariants(propertyValue, &v);
00616     
00617     DISPID dispIdPut = DISPID_PROPERTYPUT;
00618     DISPPARAMS functionArgs;
00619     _variant_t vResult;
00620     
00621     functionArgs.rgdispidNamedArgs = &dispIdPut;
00622     functionArgs.rgvarg = &v;
00623     functionArgs.cArgs = 1;
00624     functionArgs.cNamedArgs = 1;
00625 
00626     hr = disp->Invoke(
00627         dispid,
00628         IID_NULL,
00629         LOCALE_USER_DEFAULT,
00630         DISPATCH_PROPERTYPUT,
00631         &functionArgs, &vResult, NULL, NULL);
00632     
00633     if (FAILED(hr))
00634     { 
00635         return NPERR_GENERIC_ERROR;
00636     }
00637 
00638     return NS_OK;
00639 }
00640 
00641 
00643 
00644 #ifdef XPC_IDISPATCH_SUPPORT
00645 HRESULT
00646 nsEventSink::InternalInvoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
00647 {
00648     FUNCDESC *pFuncDesc = NULL;
00649     HRESULT hr = S_OK;
00650     CComBSTR bstrName;
00651 
00652     // Must search and compare each member to the dispid...
00653     if (m_spEventSinkTypeInfo)
00654     {
00655            HRESULT hr = S_OK;
00656            TYPEATTR* pAttr;
00657            hr = m_spEventSinkTypeInfo->GetTypeAttr(&pAttr);
00658         if (pAttr)
00659         {
00660                int i;
00661                for (i = 0; i < pAttr->cFuncs;i++)
00662                {
00663                       hr = m_spEventSinkTypeInfo->GetFuncDesc(i, &pFuncDesc);
00664                       if (FAILED(hr))
00665                              return hr;
00666                       if (pFuncDesc->memid == dispIdMember)
00667                 {
00668                     UINT cNames = 0;
00669                     m_spEventSinkTypeInfo->GetNames(dispIdMember, &bstrName, 1, &cNames);
00670                              break;
00671                 }
00672                 
00673                       m_spEventSinkTypeInfo->ReleaseFuncDesc(pFuncDesc);
00674                       pFuncDesc = NULL;
00675                }
00676                m_spEventSinkTypeInfo->ReleaseTypeAttr(pAttr);
00677         }
00678     }
00679     if (!pFuncDesc)
00680     {
00681         // Return
00682         return S_OK;
00683     }
00684 
00685 #ifdef DEBUG
00686     {
00687         // Dump out some info to look at
00688         ATLTRACE(_T("Invoke(%d)\n"), (int) dispIdMember);
00689 
00690         ATLTRACE(_T("  "));
00691 
00692         /* Return code */
00693         switch (pFuncDesc->elemdescFunc.tdesc.vt)
00694         {
00695         case VT_HRESULT:     ATLTRACE(_T("HRESULT")); break;
00696         case VT_VOID:        ATLTRACE(_T("void")); break;
00697         default:             ATLTRACE(_T("void /* vt = %d */"), pFuncDesc->elemdescFunc.tdesc.vt); break;
00698         }
00699 
00700         /* Function name */
00701         ATLTRACE(_T(" %S("), SUCCEEDED(hr) ? bstrName.m_str : L"?unknown?");
00702 
00703         /* Parameters */
00704         for (int i = 0; i < pFuncDesc->cParams; i++)
00705         {
00706             USHORT  paramFlags = pFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags;
00707             ATLTRACE("[");
00708             BOOL addComma = FALSE;
00709             if (paramFlags & PARAMFLAG_FIN)
00710             {
00711                 ATLTRACE(_T("in")); addComma = TRUE;
00712             }
00713             if (paramFlags & PARAMFLAG_FOUT)
00714             {
00715                 ATLTRACE(addComma ? _T(",out") : _T("out")); addComma = TRUE;
00716             }
00717             if (paramFlags & PARAMFLAG_FRETVAL)
00718             {
00719                 ATLTRACE(addComma ? _T(",retval") : _T("retval")); addComma = TRUE;
00720             }
00721             ATLTRACE("] ");
00722 
00723             VARTYPE vt = pFuncDesc->lprgelemdescParam[i].tdesc.vt;
00724             switch (vt)
00725             {
00726             case VT_HRESULT:     ATLTRACE(_T("HRESULT")); break;
00727             case VT_VARIANT:     ATLTRACE(_T("VARIANT")); break;
00728             case VT_I2:          ATLTRACE(_T("short")); break;
00729             case VT_I4:          ATLTRACE(_T("long")); break;
00730             case VT_R8:          ATLTRACE(_T("double")); break;
00731             case VT_BOOL:        ATLTRACE(_T("VARIANT_BOOL")); break;
00732             case VT_BSTR:        ATLTRACE(_T("BSTR")); break;
00733             case VT_DISPATCH:    ATLTRACE(_T("IDispatch *")); break;
00734             case VT_UNKNOWN:     ATLTRACE(_T("IUnknown *")); break;
00735             case VT_USERDEFINED: ATLTRACE(_T("/* Userdefined */")); break;
00736             case VT_PTR:         ATLTRACE(_T("void *")); break;
00737             case VT_VOID:        ATLTRACE(_T("void")); break;
00738             // More could be added...
00739             default:             ATLTRACE(_T("/* vt = %d */"), vt); break;
00740             }
00741             if (i + 1 < pFuncDesc->cParams)
00742             {
00743                 ATLTRACE(_T(", "));
00744             }
00745         }
00746         ATLTRACE(_T(");\n"));
00747     }
00748 #endif
00749     m_spEventSinkTypeInfo->ReleaseFuncDesc(pFuncDesc);
00750     pFuncDesc = NULL;
00751 
00752     nsCOMPtr<nsIDOMElement> element;
00753     NPN_GetValue(mPlugin->pPluginInstance, NPNVDOMElement, 
00754         NS_STATIC_CAST(nsIDOMElement **, getter_AddRefs(element)));
00755     if (!element)
00756     {
00757         NS_ERROR("can't get the object element");
00758         return S_OK;
00759     }
00760     nsAutoString id;
00761     if (NS_FAILED(element->GetAttribute(NS_LITERAL_STRING("id"), id)) ||
00762         id.IsEmpty())
00763     {
00764         // Object has no name so it can't fire events
00765         return S_OK;
00766     }
00767 
00768     nsDependentString eventName(bstrName.m_str);
00769 
00770     // Fire the script event handler...
00771     nsCOMPtr<nsIDOMWindow> window;
00772     NPN_GetValue(mPlugin->pPluginInstance, NPNVDOMWindow, 
00773         NS_STATIC_CAST(nsIDOMWindow **, getter_AddRefs(window)));
00774     
00775     nsCOMPtr<nsIScriptEventManager> eventManager(do_GetInterface(window));
00776     if (!eventManager) return S_OK;
00777 
00778     nsCOMPtr<nsISupports> handler;
00779 
00780     eventManager->FindEventHandler(id, eventName, pDispParams->cArgs, getter_AddRefs(handler));
00781     if (!handler)
00782     {
00783         return S_OK;
00784     }
00785 
00786     // Create a list of arguments to pass along
00787     //
00788     // This array is created on the stack if the number of arguments
00789     // less than kMaxArgsOnStack.  Otherwise, the array is heap
00790     // allocated.
00791     //
00792     const int kMaxArgsOnStack = 10;
00793 
00794     PRUint32 argc = pDispParams->cArgs;
00795     jsval *args = nsnull;
00796     jsval stackArgs[kMaxArgsOnStack];
00797 
00798     // Heap allocate the jsval array if it is too big to fit on
00799     // the stack (ie. more than kMaxArgsOnStack arguments)
00800     if (argc > kMaxArgsOnStack)
00801     {
00802         args = new jsval[argc];
00803         if (!args) return S_OK;
00804     }
00805     else if (argc)
00806     {
00807         // Use the jsval array on the stack...
00808         args = stackArgs;
00809     }
00810 
00811     if (argc)
00812     {
00813         nsCOMPtr<nsIDispatchSupport> disp(do_GetService("@mozilla.org/nsdispatchsupport;1"));
00814         for (UINT i = 0; i < argc; i++)
00815         {
00816             // Arguments are listed backwards, intentionally, in rgvarg
00817             disp->COMVariant2JSVal(&pDispParams->rgvarg[argc - 1 - i], &args[i]);
00818         }
00819     }
00820 
00821     // Fire the Event.
00822     eventManager->InvokeEventHandler(handler, element, args, argc);
00823 
00824     // Free the jsvals if they were heap allocated...
00825     if (args != stackArgs)
00826     {
00827         delete [] args;
00828     }
00829 
00830     // TODO Turn js objects for out params back into VARIANTS
00831 
00832     // TODO Turn js return code into VARIANT
00833 
00834     // TODO handle js exception and fill in exception info (do we care?)
00835 
00836     if (pExcepInfo)
00837     {
00838         pExcepInfo->wCode = 0;
00839     }
00840 
00841     return S_OK;
00842 }
00843 #endif
00844 
00845 
00848 // nsScriptablePeerTearOff
00849 
00850 nsScriptablePeerTearOff::nsScriptablePeerTearOff(nsScriptablePeer *pOwner) :
00851     mOwner(pOwner)
00852 {
00853     NS_ASSERTION(mOwner, "no owner");
00854 }
00855 
00856 HRESULT STDMETHODCALLTYPE nsScriptablePeerTearOff::QueryInterface(REFIID riid, void **ppvObject)
00857 {
00858     if (::IsEqualIID(riid, _uuidof(IDispatch)))
00859     {
00860         *ppvObject = dynamic_cast<IDispatch *>(this);
00861         mOwner->AddRef();
00862         return NS_OK;
00863     }
00864     nsID iid;
00865     memcpy(&iid, &riid, sizeof(nsID));
00866     return mOwner->QueryInterface(iid, ppvObject);
00867 }
00868 
00869 ULONG STDMETHODCALLTYPE nsScriptablePeerTearOff::AddRef()
00870 {
00871     return mOwner->AddRef();
00872 }
00873 
00874 ULONG STDMETHODCALLTYPE nsScriptablePeerTearOff::Release()
00875 {
00876     return mOwner->Release();
00877 }
00878 
00879 // IDispatch
00880 HRESULT STDMETHODCALLTYPE nsScriptablePeerTearOff::GetTypeInfoCount(UINT __RPC_FAR *pctinfo)
00881 {
00882     CComPtr<IDispatch> disp;
00883     if (FAILED(mOwner->GetIDispatch(&disp)))
00884     {
00885         return E_UNEXPECTED;
00886     }
00887     return disp->GetTypeInfoCount(pctinfo);
00888 }
00889 
00890 HRESULT STDMETHODCALLTYPE nsScriptablePeerTearOff::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo)
00891 {
00892     CComPtr<IDispatch> disp;
00893     if (FAILED(mOwner->GetIDispatch(&disp)))
00894     {
00895         return E_UNEXPECTED;
00896     }
00897     return disp->GetTypeInfo(iTInfo, lcid, ppTInfo);
00898 }
00899 
00900 HRESULT STDMETHODCALLTYPE nsScriptablePeerTearOff::GetIDsOfNames(REFIID riid, LPOLESTR __RPC_FAR *rgszNames, UINT cNames, LCID lcid, DISPID __RPC_FAR *rgDispId)
00901 {
00902     CComPtr<IDispatch> disp;
00903     if (FAILED(mOwner->GetIDispatch(&disp)))
00904     {
00905         return E_UNEXPECTED;
00906     }
00907     return disp->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispId);
00908 }
00909 
00910 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)
00911 {
00912     CComPtr<IDispatch> disp;
00913     if (FAILED(mOwner->GetIDispatch(&disp)))
00914     {
00915         return E_UNEXPECTED;
00916     }
00917     return disp->Invoke(dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
00918 }
00919 
00920 
00923 // Some public methods
00924 
00925 
00926 static PRUint32 gInstances = 0;
00927 
00928 void MozAxPlugin::AddRef()
00929 {
00930     if (gInstances == 0)
00931     {
00932 #ifdef XPCOM_GLUE
00933         XPCOMGlueStartup(nsnull);
00934 #endif
00935         MozAxPlugin::PrefGetHostingFlags(); // Initial call to set it up
00936     }
00937     gInstances++;
00938 }
00939 
00940 void MozAxPlugin::Release()
00941 {
00942     if (--gInstances == 0)
00943     {
00944 #ifdef XPC_IDISPATCH_SUPPORT
00945         MozAxPlugin::ReleasePrefObserver();
00946 #endif
00947 #ifdef XPCOM_GLUE
00948         XPCOMGlueShutdown();
00949 #endif
00950     }
00951 }
00952 
00953 #ifdef XPC_IDISPATCH_SUPPORT
00954 nsresult MozAxPlugin::GetCurrentLocation(NPP instance, nsIURI **aLocation)
00955 {
00956     NS_ENSURE_ARG_POINTER(aLocation);
00957     *aLocation = nsnull;
00958     nsCOMPtr<nsIDOMWindow> domWindow;
00959     NPN_GetValue(instance, NPNVDOMWindow, (void *) &domWindow);
00960     if (!domWindow)
00961     {
00962         return NS_ERROR_FAILURE;
00963     }
00964     nsCOMPtr<nsIDOMWindowInternal> windowInternal = do_QueryInterface(domWindow);
00965     if (!windowInternal)
00966     {
00967         return NS_ERROR_FAILURE;
00968     }
00969 
00970     nsCOMPtr<nsIDOMLocation> location;
00971 #ifdef XPCOM_GLUE
00972     nsEmbedString href;
00973 #else
00974     nsAutoString href;
00975 #endif
00976     windowInternal->GetLocation(getter_AddRefs(location));
00977     if (!location ||
00978         NS_FAILED(location->GetHref(href)))
00979     {
00980         return NS_ERROR_FAILURE;
00981     }
00982 
00983     return NS_NewURI(aLocation, href);
00984 }
00985 #endif
00986 
00987 CLSID MozAxPlugin::GetCLSIDForType(const char *mimeType)
00988 {
00989     if (mimeType == NULL)
00990     {
00991         return CLSID_NULL;
00992     }
00993 
00994     // Read the registry to see if there is a CLSID for an object to be associated with
00995     // this MIME type.
00996     USES_CONVERSION;
00997     CRegKey keyMimeDB;
00998     if (keyMimeDB.Open(HKEY_CLASSES_ROOT, _T("MIME\\Database\\Content Type"), KEY_READ) == ERROR_SUCCESS)
00999     {
01000         CRegKey keyMimeType;
01001         if (keyMimeType.Open(keyMimeDB, A2CT(mimeType), KEY_READ) == ERROR_SUCCESS)
01002         {
01003                USES_CONVERSION;
01004                TCHAR szGUID[64];
01005                ULONG nCount = (sizeof(szGUID) / sizeof(szGUID[0])) - 1;
01006 
01007             GUID guidValue = GUID_NULL;
01008             if (keyMimeType.QueryValue(szGUID, _T("CLSID"), &nCount) == ERROR_SUCCESS &&
01009                 SUCCEEDED(::CLSIDFromString(T2OLE(szGUID), &guidValue)))
01010             {
01011                 return guidValue;
01012             }
01013         }
01014     }
01015     return CLSID_NULL;
01016 }
01017 
01018 
01019 nsScriptablePeer *
01020 MozAxPlugin::GetPeerForCLSID(const CLSID &clsid)
01021 {
01022     return new nsScriptablePeer();
01023 }
01024 
01025 void
01026 MozAxPlugin::GetIIDForCLSID(const CLSID &clsid, nsIID &iid)
01027 {
01028 #ifdef XPC_IDISPATCH_SUPPORT
01029     memcpy(&iid, &__uuidof(IDispatch), sizeof(iid));
01030 #else
01031     iid = NS_GET_IID(nsIMozAxPlugin);
01032 #endif
01033 }
01034 
01035 // Called by NPP_GetValue to provide the scripting values
01036 NPError
01037 MozAxPlugin::GetValue(NPP instance, NPPVariable variable, void *value)
01038 {
01039     if (instance == NULL)
01040     {
01041         return NPERR_INVALID_INSTANCE_ERROR;
01042     }
01043 
01044     PluginInstanceData *pData = (PluginInstanceData *) instance->pdata;
01045     if (!pData ||
01046         !pData->pControlSite ||
01047         !pData->pControlSite->IsObjectValid())
01048     {
01049         return NPERR_GENERIC_ERROR;
01050     }
01051 
01052     // Test if the object is allowed to be scripted
01053 
01054 #ifdef XPC_IDISPATCH_SUPPORT
01055     PRUint32 hostingFlags = MozAxPlugin::PrefGetHostingFlags();
01056     if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_SAFE_OBJECTS &&
01057         !(hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_ALL_OBJECTS))
01058     {
01059         // Ensure the object is safe for scripting on the specified interface
01060         nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID);
01061         if (!dispSupport) return NPERR_GENERIC_ERROR;
01062         
01063         PRBool isScriptable = PR_FALSE;
01064 
01065         // Test if the object says its safe for scripting on IDispatch
01066         nsIID iid;
01067         memcpy(&iid, &__uuidof(IDispatch), sizeof(iid));
01068         CComPtr<IUnknown> controlUnk;
01069         pData->pControlSite->GetControlUnknown(&controlUnk);
01070         dispSupport->IsObjectSafeForScripting(reinterpret_cast<void *>(controlUnk.p), iid, &isScriptable);
01071 
01072         // Test if the class id says safe for scripting
01073         if (!isScriptable)
01074         {
01075             PRBool classExists = PR_FALSE;
01076             nsCID cid;
01077             memcpy(&cid, &pData->clsid, sizeof(cid));
01078             dispSupport->IsClassMarkedSafeForScripting(cid, &classExists, &isScriptable);
01079         }
01080         if (!isScriptable)
01081         {
01082             return NPERR_GENERIC_ERROR;
01083         }
01084     }
01085     else if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_ALL_OBJECTS)
01086     {
01087         // Drop through since all objects are scriptable
01088     }
01089     else
01090     {
01091         return NPERR_GENERIC_ERROR;
01092     }
01093 #else
01094     // Object *must* be safe
01095     if (!pData->pControlSite->IsObjectSafeForScripting(__uuidof(IDispatch)))
01096     {
01097         return NPERR_GENERIC_ERROR;
01098     }
01099 #endif
01100 
01101     // Happy happy fun fun - redefine some NPPVariable values that we might
01102     // be asked for but not defined by every PluginSDK 
01103 
01104     const int kVarScriptableInstance = 10; // NPPVpluginScriptableInstance
01105     const int kVarScriptableIID = 11; // NPPVpluginScriptableIID
01106 
01107     if (variable == kVarScriptableInstance)
01108     {
01109         if (!pData->pScriptingPeer)
01110         {
01111             nsScriptablePeer *peer = MozAxPlugin::GetPeerForCLSID(pData->clsid);
01112             if (peer)
01113             {
01114                 peer->AddRef();
01115                 pData->pScriptingPeer = (nsIMozAxPlugin *) peer;
01116                 peer->mPlugin = pData;
01117             }
01118         }
01119         if (pData->pScriptingPeer)
01120         {
01121             pData->pScriptingPeer->AddRef();
01122             *((nsISupports **) value)= pData->pScriptingPeer;
01123             return NPERR_NO_ERROR;
01124         }
01125     }
01126     else if (variable == kVarScriptableIID)
01127     {
01128         nsIID *piid = (nsIID *) NPN_MemAlloc(sizeof(nsIID));
01129         GetIIDForCLSID(pData->clsid, *piid);
01130         *((nsIID **) value) = piid;
01131         return NPERR_NO_ERROR;
01132     }
01133     return NPERR_GENERIC_ERROR;
01134 }
01135 
01136 
01137