Back to index

lightning-sunbird  0.9+nobinonly
XPCDispTypeInfo.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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 the IDispatch implementation for XPConnect.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * David Bradley.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00050 #include "xpcprivate.h"
00051 
00052 // There's no CPP for XPCDispNameArray so it's just plopped here
00053 const nsString XPCDispNameArray::sEmpty;
00054 
00061 inline
00062 void FillOutElemDesc(VARTYPE vt, PRUint16 paramFlags, ELEMDESC & elemDesc)
00063 {
00064     elemDesc.tdesc.vt = vt;
00065     elemDesc.paramdesc.wParamFlags = paramFlags;
00066     elemDesc.paramdesc.pparamdescex = 0;
00067     elemDesc.tdesc.lptdesc = 0;
00068     elemDesc.tdesc.lpadesc = 0;
00069     elemDesc.tdesc.hreftype = 0;
00070 }
00071 
00072 XPCDispTypeInfo::~XPCDispTypeInfo()
00073 {
00074     delete mIDArray;
00075 }
00076 
00077 void XPCDispJSPropertyInfo::GetReturnType(XPCCallContext& ccx, ELEMDESC & elemDesc)
00078 {
00079     VARTYPE vt;
00080     if(IsSetter())      // if this is a setter
00081     {
00082         vt = VT_EMPTY;
00083     }
00084     else if(IsProperty())   // If this is a property
00085     {
00086         vt = XPCDispConvert::JSTypeToCOMType(ccx, mProperty);
00087     }
00088     else                    // if this is a function
00089     {
00090         vt = VT_VARIANT;
00091     }
00092     FillOutElemDesc(vt, PARAMFLAG_FRETVAL, elemDesc);
00093 }
00094 
00095 ELEMDESC* XPCDispJSPropertyInfo::GetParamInfo()
00096 {
00097     PRUint32 paramCount = GetParamCount();
00098     ELEMDESC* elemDesc;
00099     if(paramCount != 0)
00100     {
00101         elemDesc = new ELEMDESC[paramCount];
00102         if(elemDesc)
00103         {
00104             for(PRUint32 index = 0; index < paramCount; ++index)
00105             {
00106                 FillOutElemDesc(VT_VARIANT, PARAMFLAG_FIN, elemDesc[index]);
00107             }
00108         }
00109     }
00110     else
00111         elemDesc = 0;
00112     // Caller becomes owner
00113     return elemDesc;
00114 }
00115 
00116 XPCDispJSPropertyInfo::XPCDispJSPropertyInfo(JSContext* cx, PRUint32 memid, 
00117                                              JSObject* obj, jsval val) : 
00118     mPropertyType(INVALID), mMemID(memid)
00119 {
00120     PRUint32 len;
00121     jschar * chars = xpc_JSString2String(cx, val, &len);
00122     if(!chars)
00123         return;
00124 
00125     mName = nsString(NS_REINTERPRET_CAST(const PRUnichar *, chars), len);
00126     JSBool found;
00127     uintN attr;
00128     // Get the property's attributes, and make sure it's found and enumerable 
00129     if(!JS_GetUCPropertyAttributes(cx, obj, chars, len, &attr, &found) || 
00130         !found || (attr & JSPROP_ENUMERATE) == 0)
00131         return;
00132 
00133     // Retrieve the property 
00134     if(!chars || !JS_GetUCProperty(cx, obj, chars, len, &mProperty) ||
00135         JSVAL_IS_NULL(mProperty))
00136         return;
00137 
00138     // If this is a function
00139     if(JSVAL_IS_OBJECT(mProperty) && 
00140         JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(mProperty)))
00141     {
00142         mPropertyType = FUNCTION;
00143         JSObject * funcObj = JSVAL_TO_OBJECT(mProperty);
00144         JSIdArray * funcObjArray = JS_Enumerate(cx, funcObj);
00145         if(funcObjArray)
00146         {
00147             mParamCount = funcObjArray->length;
00148         }
00149     }
00150     else // It's a property
00151     {
00152         mParamCount = 0;
00153         if((attr & JSPROP_READONLY) != 0)
00154         {
00155             mPropertyType = READONLY_PROPERTY;
00156         }
00157         else
00158         {
00159             mPropertyType = PROPERTY;
00160         }
00161     }
00162 }
00163 
00164 PRBool XPCDispTypeInfo::FuncDescArray::BuildFuncDesc(XPCCallContext& ccx, JSObject* obj, 
00165                                      XPCDispJSPropertyInfo & propInfo)
00166 {
00167     // While this memory is passed out, we're ultimately responsible to free it
00168     FUNCDESC* funcDesc = new FUNCDESC;
00169     if(!funcDesc)
00170         return PR_FALSE;
00171     mArray.AppendElement(funcDesc);
00172     // zero is reserved
00173     funcDesc->memid = propInfo.GetMemID();
00174     funcDesc->lprgscode = 0; // Not used (for 16 bit systems)
00175     funcDesc->funckind = FUNC_DISPATCH;
00176     funcDesc->invkind = propInfo.GetInvokeKind();
00177     funcDesc->callconv = CC_STDCALL;
00178     funcDesc->cParams = propInfo.GetParamCount();
00179     funcDesc->lprgelemdescParam = propInfo.GetParamInfo();
00180     // We might want to make all parameters optional since JS can handle that
00181     funcDesc->cParamsOpt = 0; // Optional parameters
00182     // This could be a problem, supposed to be used for functions of
00183     // type FUNC_VIRTUAL which we aren't, so zero should be ok
00184     funcDesc->oVft = 0;         // Specifies offset in VTBL for FUNC_VIRTUAL
00185     funcDesc->cScodes = 0;      // Counts the permitted return values.
00186     funcDesc->wFuncFlags = 0;   // Indicates the FUNCFLAGS of a function.
00187     propInfo.GetReturnType(ccx, funcDesc->elemdescFunc);
00188     return PR_TRUE;
00189 }
00190 
00191 XPCDispTypeInfo::FuncDescArray::FuncDescArray(XPCCallContext& ccx, JSObject* obj, const XPCDispIDArray& array, XPCDispNameArray & names)
00192 {
00193     PRUint32 size = array.Length();
00194     names.SetSize(size);
00195     PRUint32 memid = 0;
00196     JSContext* cx = ccx;
00197     // Initialize each function description in the array
00198     for(PRUint32 index = 0; index < size; ++index)
00199     {
00200         XPCDispJSPropertyInfo propInfo(cx, ++memid, obj, array.Item(cx, index));
00201         names.SetName(index + 1, propInfo.GetName());
00202         if(!BuildFuncDesc(ccx, obj, propInfo))
00203             return;
00204         // non-readonly Properties get two function descriptions
00205         if(propInfo.IsProperty() && !propInfo.IsReadOnly())
00206         {
00207             propInfo.SetSetter();
00208             if(!BuildFuncDesc(ccx, obj, propInfo))
00209                 return;
00210         }
00211     }
00212 }
00213 
00214 XPCDispTypeInfo::FuncDescArray::~FuncDescArray()
00215 {
00216     PRUint32 size = mArray.Count();
00217     for(PRUint32 index = 0; index < size; ++index)
00218     {
00219         FUNCDESC* funcDesc = NS_REINTERPRET_CAST(FUNCDESC*,mArray.ElementAt(index));
00220         delete [] funcDesc->lprgelemdescParam;
00221         delete funcDesc;
00222     }
00223 }
00224 
00225 XPCDispTypeInfo::XPCDispTypeInfo(XPCCallContext& ccx, JSObject* obj, 
00226                                XPCDispIDArray* array) :
00227     mRefCnt(0), mJSObject(obj), mIDArray(array), 
00228     mFuncDescArray(ccx, obj, *array, mNameArray)
00229 {
00230 }
00231 
00232 XPCDispTypeInfo * XPCDispTypeInfo::New(XPCCallContext& ccx, JSObject* obj)
00233 {
00234     XPCDispTypeInfo * pTypeInfo = 0;
00235     JSIdArray * jsArray = JS_Enumerate(ccx, obj);
00236     if(!jsArray)
00237         return nsnull;
00238     XPCDispIDArray* array = new XPCDispIDArray(ccx, jsArray);
00239     if(!array)
00240         return nsnull;
00241     pTypeInfo = new XPCDispTypeInfo(ccx, obj, array);
00242     if(!pTypeInfo)
00243     {
00244         delete array;
00245         return nsnull;
00246     }
00247     NS_ADDREF(pTypeInfo);
00248     return pTypeInfo;
00249 }
00250 
00251 NS_COM_MAP_BEGIN(XPCDispTypeInfo)
00252     NS_COM_MAP_ENTRY(ITypeInfo)
00253     NS_COM_MAP_ENTRY(IUnknown)
00254 NS_COM_MAP_END
00255 
00256 NS_IMPL_THREADSAFE_ADDREF(XPCDispTypeInfo)
00257 NS_IMPL_THREADSAFE_RELEASE(XPCDispTypeInfo)
00258 
00259 
00260 STDMETHODIMP XPCDispTypeInfo::GetTypeAttr( 
00261     /* [out] */ TYPEATTR __RPC_FAR *__RPC_FAR *ppTypeAttr)
00262 {
00263     return E_NOTIMPL;
00264 }
00265     
00266 STDMETHODIMP XPCDispTypeInfo::GetTypeComp(
00267     /* [out] */ ITypeComp __RPC_FAR *__RPC_FAR *ppTComp)
00268 {
00269     return E_NOTIMPL;
00270 }
00271 
00272 STDMETHODIMP XPCDispTypeInfo::GetFuncDesc(
00273         /* [in] */ UINT index,
00274         /* [out] */ FUNCDESC __RPC_FAR *__RPC_FAR *ppFuncDesc)
00275 {
00276     return E_NOTIMPL;
00277 }
00278     
00279 STDMETHODIMP XPCDispTypeInfo::GetVarDesc(
00280         /* [in] */ UINT index,
00281         /* [out] */ VARDESC __RPC_FAR *__RPC_FAR *ppVarDesc)
00282 {
00283     return E_NOTIMPL;
00284 }
00285     
00286 STDMETHODIMP XPCDispTypeInfo::GetNames(
00287         /* [in] */ MEMBERID memid,
00288         /* [length_is][size_is][out] */ BSTR __RPC_FAR *rgBstrNames,
00289         /* [in] */ UINT cMaxNames,
00290         /* [out] */ UINT __RPC_FAR *pcNames)
00291 {
00292     return E_NOTIMPL;
00293 }
00294     
00295 STDMETHODIMP XPCDispTypeInfo::GetRefTypeOfImplType(
00296         /* [in] */ UINT index,
00297         /* [out] */ HREFTYPE __RPC_FAR *pRefType)
00298 {
00299     return E_NOTIMPL;
00300 }
00301     
00302 STDMETHODIMP XPCDispTypeInfo::GetImplTypeFlags(
00303         /* [in] */ UINT index,
00304         /* [out] */ INT __RPC_FAR *pImplTypeFlags)
00305 {
00306     return E_NOTIMPL;
00307 }
00308 
00309 STDMETHODIMP XPCDispTypeInfo::GetIDsOfNames(
00310         /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames,
00311         /* [in] */ UINT cNames,
00312         /* [size_is][out] */ MEMBERID __RPC_FAR *pMemId)
00313 {
00314     // lookup each name
00315     for(UINT index = 0; index < cNames; ++index)
00316     {
00317         nsDependentString buffer(NS_STATIC_CAST(const PRUnichar *,
00318                                  rgszNames[index]),
00319                                  wcslen(rgszNames[index]));
00320         pMemId[index] = mNameArray.Find(buffer);
00321 
00322     }
00323     return S_OK;
00324 }
00325 
00326 STDMETHODIMP XPCDispTypeInfo::Invoke(
00327         /* [in] */ PVOID pvInstance,
00328         /* [in] */ MEMBERID memid,
00329         /* [in] */ WORD wFlags,
00330         /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams,
00331         /* [out] */ VARIANT __RPC_FAR *pVarResult,
00332         /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo,
00333         /* [out] */ UINT __RPC_FAR *puArgErr)
00334 {
00335     CComQIPtr<IDispatch> pDisp(NS_REINTERPRET_CAST(IUnknown*,pvInstance));
00336     if(pDisp)
00337     {
00338         return pDisp->Invoke(memid, IID_NULL, LOCALE_SYSTEM_DEFAULT, wFlags, 
00339                                pDispParams, pVarResult, pExcepInfo, puArgErr);
00340     }
00341     return E_NOINTERFACE;
00342 }
00343     
00344 STDMETHODIMP XPCDispTypeInfo::GetDocumentation(
00345         /* [in] */ MEMBERID memid,
00346         /* [out] */ BSTR __RPC_FAR *pBstrName,
00347         /* [out] */ BSTR __RPC_FAR *pBstrDocString,
00348         /* [out] */ DWORD __RPC_FAR *pdwHelpContext,
00349         /* [out] */ BSTR __RPC_FAR *pBstrHelpFile)
00350 {
00351     PRUint32 index = memid;
00352     if(index < mIDArray->Length())
00353         return E_FAIL;
00354 
00355     XPCCallContext ccx(NATIVE_CALLER);
00356     PRUnichar * chars = xpc_JSString2PRUnichar(ccx, mIDArray->Item(ccx, index));
00357     if(!chars)
00358     {
00359         return E_FAIL;
00360     }
00361     CComBSTR name(chars);
00362     *pBstrName = name.Detach();
00363     pBstrDocString = 0;
00364     pdwHelpContext = 0;
00365     pBstrHelpFile = 0;
00366     return S_OK;
00367 }
00368     
00369 STDMETHODIMP XPCDispTypeInfo::GetDllEntry(
00370         /* [in] */ MEMBERID memid,
00371         /* [in] */ INVOKEKIND invKind,
00372         /* [out] */ BSTR __RPC_FAR *pBstrDllName,
00373         /* [out] */ BSTR __RPC_FAR *pBstrName,
00374         /* [out] */ WORD __RPC_FAR *pwOrdinal)
00375 {
00376     // We are not supporting this till a need arrises
00377     return E_NOTIMPL;
00378 }
00379     
00380 STDMETHODIMP XPCDispTypeInfo::GetRefTypeInfo(
00381         /* [in] */ HREFTYPE hRefType,
00382         /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo)
00383 {
00384     return E_NOTIMPL;
00385 }
00386     
00387 STDMETHODIMP XPCDispTypeInfo::AddressOfMember(
00388         /* [in] */ MEMBERID memid,
00389         /* [in] */ INVOKEKIND invKind,
00390         /* [out] */ PVOID __RPC_FAR *ppv)
00391 {
00392     // We are not supporting this till a need arrises
00393     return E_NOTIMPL;
00394 }
00395     
00396 STDMETHODIMP XPCDispTypeInfo::CreateInstance(
00397         /* [in] */ IUnknown __RPC_FAR *pUnkOuter,
00398         /* [in] */ REFIID riid,
00399         /* [iid_is][out] */ PVOID __RPC_FAR *ppvObj)
00400 {
00401     // We are not supporting this till a need arrises
00402     return E_NOTIMPL;
00403 }
00404     
00405 STDMETHODIMP XPCDispTypeInfo::GetMops(
00406         /* [in] */ MEMBERID memid,
00407         /* [out] */ BSTR __RPC_FAR *pBstrMops)
00408 {
00409     return E_NOTIMPL;
00410 }
00411     
00412 STDMETHODIMP XPCDispTypeInfo::GetContainingTypeLib(
00413         /* [out] */ ITypeLib __RPC_FAR *__RPC_FAR *ppTLib,
00414         /* [out] */ UINT __RPC_FAR *pIndex)
00415 {
00416     // We are not supporting this till a need arrises
00417     return E_NOTIMPL;
00418 }
00419     
00420 void STDMETHODCALLTYPE XPCDispTypeInfo::ReleaseTypeAttr( 
00421     /* [in] */ TYPEATTR __RPC_FAR *pTypeAttr)
00422 {
00423     // Nothing for us to do
00424 }
00425 
00426 void STDMETHODCALLTYPE XPCDispTypeInfo::ReleaseFuncDesc( 
00427     /* [in] */ FUNCDESC __RPC_FAR *pFuncDesc)
00428 {
00429     // Nothing for us to do
00430 }
00431 
00432 void STDMETHODCALLTYPE XPCDispTypeInfo::ReleaseVarDesc( 
00433     /* [in] */ VARDESC __RPC_FAR *pVarDesc)
00434 {
00435     // Nothing for us to do
00436 }
00437 
00438 XPCDispIDArray::XPCDispIDArray(XPCCallContext& ccx, JSIdArray* array) : 
00439     mMarked(JS_FALSE), mIDArray(array->length)
00440 {
00441     // copy the JS ID Array to our internal array
00442     for(jsint index = 0; index < array->length; ++index)
00443     {
00444         mIDArray.ReplaceElementAt(NS_REINTERPRET_CAST(void*,
00445                                                       array->vector[index]), 
00446                                   index);
00447     }   
00448 }
00449 
00450 void XPCDispIDArray::Mark()
00451 {
00452     // If already marked nothing to do
00453     if(IsMarked())
00454         return;
00455     mMarked = JS_TRUE;
00456     XPCCallContext ccx(NATIVE_CALLER);
00457     // Bail if our call context is bad
00458     if(!ccx.IsValid())
00459         return;
00460 
00461     PRInt32 count = Length();
00462     jsval val;
00463     JSContext* cx = ccx;
00464     // Iterate each of the ID's and mark them
00465     for(PRInt32 index = 0; index < count; ++index)
00466     {
00467         if(JS_IdToValue(cx,
00468                         NS_REINTERPRET_CAST(jsid,
00469                                             mIDArray.ElementAt(index)),
00470                         &val) &&
00471             JSVAL_IS_GCTHING(val))
00472         {
00473             JS_MarkGCThing(cx, NS_REINTERPRET_CAST(void*,val),
00474                            nsnull, nsnull);
00475         }
00476     }
00477 }
00478