Back to index

lightning-sunbird  0.9+nobinonly
Public Member Functions | Private Member Functions | Private Attributes
XPCDispatchTearOff Class Reference

Tearoff for nsXPCWrappedJS to use. More...

#include <XPCDispPrivate.h>

Inheritance diagram for XPCDispatchTearOff:
Inheritance graph
[legend]
Collaboration diagram for XPCDispatchTearOff:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 XPCDispatchTearOff (nsIXPConnectWrappedJS *wrappedJS)
 Constructor initializes our COM pointer back to our main object.
virtual ~XPCDispatchTearOff ()
 Release the our allocated data, and decrements our main objects refcnt.
STDMETHOD() InterfaceSupportsErrorInfo (REFIID riid)
 Error handling function.
 STDMETHODIMP_ (ULONG) AddRef()
 Thread safe AddRef.
 STDMETHODIMP_ (ULONG) Release()
 Thread safe Release.
STDMETHOD() QueryInterface (REFIID IID, void **pPtr)
 QueryInterface that returns us or the main object See MSDN for form information.
STDMETHOD() GetTypeInfoCount (unsigned int *pctinfo)
 Returns the number of type info's for this IDispatch instance.
STDMETHOD() GetTypeInfo (unsigned int iTInfo, LCID lcid, ITypeInfo FAR *FAR *ppTInfo)
 Returns the type information for this IDispatch instance See MSDN for form information.
STDMETHOD() GetIDsOfNames (REFIID riid, OLECHAR FAR *FAR *rgszNames, unsigned int cNames, LCID lcid, DISPID FAR *rgDispId)
 Returns the ID's for the given names of methods See MSDN for form information.
STDMETHOD() Invoke (DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pDispParams, VARIANT FAR *pVarResult, EXCEPINFO FAR *pExcepInfo, unsigned int FAR *puArgErr)
 Invokes an interface method See MSDN for form information.

Private Member Functions

XPCDispTypeInfoGetCOMTypeInfo ()
JSObjectGetJSObject ()

Private Attributes

nsCOMPtr< nsIXPConnectWrappedJSmWrappedJS
XPCDispTypeInfomCOMTypeInfo
ULONG mRefCnt
 NS_DECL_OWNINGTHREAD

Detailed Description

Tearoff for nsXPCWrappedJS to use.

Definition at line 601 of file XPCDispPrivate.h.


Constructor & Destructor Documentation

Constructor initializes our COM pointer back to our main object.

Definition at line 126 of file XPCDispTearOff.cpp.

                                                                        :
    mWrappedJS(wrappedJS),
    mCOMTypeInfo(nsnull),
    mRefCnt(0)
{
}

Release the our allocated data, and decrements our main objects refcnt.

Definition at line 133 of file XPCDispTearOff.cpp.


Member Function Documentation

Definition at line 196 of file XPCDispTearOff.cpp.

{
    // If one was already created return it
    if(mCOMTypeInfo)
        return mCOMTypeInfo;
    // Build a new one, save the pointer and return it
    XPCCallContext ccx(NATIVE_CALLER);
    if(!ccx.IsValid())
        return nsnull;
    JSObject* obj = GetJSObject();
    if(!obj)
        return nsnull;
    mCOMTypeInfo = XPCDispTypeInfo::New(ccx, obj);
    NS_IF_ADDREF(mCOMTypeInfo);
    return mCOMTypeInfo;
}

Here is the call graph for this function:

Here is the caller graph for this function:

STDMETHODIMP XPCDispatchTearOff::GetIDsOfNames ( REFIID  riid,
OLECHAR FAR *FAR rgszNames,
unsigned int  cNames,
LCID  lcid,
DISPID FAR rgDispId 
)

Returns the ID's for the given names of methods See MSDN for form information.

Returns:
HRESULT

Definition at line 221 of file XPCDispTearOff.cpp.

{
    ITypeInfo * pTypeInfo = GetCOMTypeInfo();
    if(pTypeInfo != nsnull)
    {
        return pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId);
    }
    return S_OK;
}

Here is the call graph for this function:

JSObject * XPCDispatchTearOff::GetJSObject ( ) [inline, private]

Definition at line 555 of file XPCDispTearOff.cpp.

{
    JSObject* obj;
    if(NS_SUCCEEDED(mWrappedJS->GetJSObject(&obj)))
        return obj;
    return nsnull;
}

Here is the caller graph for this function:

STDMETHODIMP XPCDispatchTearOff::GetTypeInfo ( unsigned int  iTInfo,
LCID  lcid,
ITypeInfo FAR *FAR ppTInfo 
)

Returns the type information for this IDispatch instance See MSDN for form information.

Returns:
HRESULT

Definition at line 213 of file XPCDispTearOff.cpp.

{
    *ppTInfo = GetCOMTypeInfo();
    NS_ADDREF(*ppTInfo);
    return S_OK;
}

Here is the call graph for this function:

STDMETHODIMP XPCDispatchTearOff::GetTypeInfoCount ( unsigned int pctinfo)

Returns the number of type info's for this IDispatch instance.

See MSDN for form information

Parameters:
pctinfopointer to the variable to receive the count
Returns:
HRESULT

Definition at line 190 of file XPCDispTearOff.cpp.

{
    *pctinfo = 1;
    return S_OK;
}
STDMETHODIMP XPCDispatchTearOff::InterfaceSupportsErrorInfo ( REFIID  riid)

Error handling function.

Parameters:
riidthe interface IID of the error

Definition at line 155 of file XPCDispTearOff.cpp.

{
    static const IID* arr[] = 
    {
        &IID_IDispatch,
    };

    for(int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
    {
        if(_IsEqualGUID(*arr[i],riid))
            return S_OK;
    }
    return S_FALSE;
}

Here is the call graph for this function:

STDMETHODIMP XPCDispatchTearOff::Invoke ( DISPID  dispIdMember,
REFIID  riid,
LCID  lcid,
WORD  wFlags,
DISPPARAMS FAR pDispParams,
VARIANT FAR pVarResult,
EXCEPINFO FAR pExcepInfo,
unsigned int FAR puArgErr 
)

Invokes an interface method See MSDN for form information.

Returns:
HRESULT

Definition at line 238 of file XPCDispTearOff.cpp.

{
    XPCDispTypeInfo* pTypeInfo = GetCOMTypeInfo();
    if(!pTypeInfo)
    {
        return E_FAIL;
    }
    XPCCallContext ccx(NATIVE_CALLER);
    XPCContext* xpcc;
    JSContext* cx;
    if(ccx.IsValid())
    {
        xpcc = ccx.GetXPCContext();
        cx = ccx.GetJSContext();
    }
    else
    {
        xpcc = nsnull;
        cx = nsnull;
    }
    // Get the name as a flat string
    // This isn't that efficient, but we have to make the conversion somewhere
    NS_LossyConvertUCS2toASCII name(pTypeInfo->GetNameForDispID(dispIdMember));
    if(name.IsEmpty())
        return E_FAIL;
    // Decide if this is a getter or setter
    PRBool getter = (wFlags & DISPATCH_PROPERTYGET) != 0;
    PRBool setter = (wFlags & DISPATCH_PROPERTYPUT) != 0;
    // It's a property
    if(getter || setter)
    {
        jsval val;
        uintN err;
        JSObject* obj;
        if(getter)
        {
            // Get the property and convert the value
            obj = GetJSObject();
            if(!obj)
                return E_FAIL;
            if(!JS_GetProperty(cx, obj, name.get(), &val))
            {
                nsCString msg("Unable to retrieve property ");
                msg += name;
                return Error(E_FAIL, msg.get());
            }
            if(!XPCDispConvert::JSToCOM(ccx, val, *pVarResult, err))
            {
                nsCString msg("Failed to convert value from JS property ");
                msg += name;
                return Error(E_FAIL, msg.get());
            }
        }
        else if(pDispParams->cArgs > 0)
        {
            // Convert the property and then set it
            if(!XPCDispConvert::COMToJS(ccx, pDispParams->rgvarg[0], val, err))
            {
                nsCString msg("Failed to convert value for JS property ");
                msg += name;
                return Error(E_FAIL, msg.get());
            }
            AUTO_MARK_JSVAL(ccx, &val);
            obj = GetJSObject();
            if(!obj)
                return Error(E_FAIL, "The JS wrapper did not return a JS object");
            if(!JS_SetProperty(cx, obj, name.get(), &val))
            {
                nsCString msg("Unable to set property ");
                msg += name;
                return Error(E_FAIL, msg.get());
            }
        }
    }
    else // We're invoking a function
    {
        jsval* stackbase;
        jsval* sp = nsnull;
        uint8 i;
        uint8 argc = pDispParams->cArgs;
        uint8 stack_size;
        jsval result;
        uint8 paramCount=0;
        nsresult retval = NS_ERROR_FAILURE;
        nsresult pending_result = NS_OK;
        JSBool success;
        JSBool readyToDoTheCall = JS_FALSE;
        uint8 outConversionFailedIndex;
        JSObject* obj;
        jsval fval;
        nsCOMPtr<nsIException> xpc_exception;
        void* mark;
        JSBool foundDependentParam;
        JSObject* thisObj;
        AutoScriptEvaluate scriptEval(ccx);
        XPCJSRuntime* rt = ccx.GetRuntime();

        thisObj = obj = GetJSObject();;

        if(!cx || !xpcc)
            goto pre_call_clean_up;

        scriptEval.StartEvaluating(xpcWrappedJSErrorReporter);

        xpcc->SetPendingResult(pending_result);
        xpcc->SetException(nsnull);
        ccx.GetThreadData()->SetException(nsnull);

        // We use js_AllocStack, js_Invoke, and js_FreeStack so that the gcthings
        // we use as args will be rooted by the engine as we do conversions and
        // prepare to do the function call. This adds a fair amount of complexity,
        // but is a good optimization compared to calling JS_AddRoot for each item.

        // setup stack

        // allocate extra space for function and 'this'
        stack_size = argc + 2;


        // In the xpidl [function] case we are making sure now that the 
        // JSObject is callable. If it is *not* callable then we silently 
        // fallback to looking up the named property...
        // (because jst says he thinks this fallback is 'The Right Thing'.)
        //
        // In the normal (non-function) case we just lookup the property by 
        // name and as long as the object has such a named property we go ahead
        // and try to make the call. If it turns out the named property is not
        // a callable object then the JS engine will throw an error and we'll
        // pass this along to the caller as an exception/result code.
        fval = OBJECT_TO_JSVAL(obj);
        if(JS_TypeOfValue(ccx, fval) != JSTYPE_FUNCTION && 
            !JS_GetProperty(cx, obj, name.get(), &fval))
        {
            // XXX We really want to factor out the error reporting better and
            // specifically report the failure to find a function with this name.
            // This is what we do below if the property is found but is not a
            // function. We just need to factor better so we can get to that
            // reporting path from here.
            goto pre_call_clean_up;
        }

        // if stack_size is zero then we won't be needing a stack
        if(stack_size && !(stackbase = sp = js_AllocStack(cx, stack_size, &mark)))
        {
            retval = NS_ERROR_OUT_OF_MEMORY;
            goto pre_call_clean_up;
        }

        // this is a function call, so push function and 'this'
        if(stack_size != argc)
        {
            *sp++ = fval;
            *sp++ = OBJECT_TO_JSVAL(thisObj);
        }

        // make certain we leave no garbage in the stack
        for(i = 0; i < argc; i++)
        {
            sp[i] = JSVAL_VOID;
        }

        uintN err;
        // build the args
        for(i = 0; i < argc; i++)
        {
            jsval val;
            if((pDispParams->rgvarg[i].vt & VT_BYREF) == 0)
            {
                if(!XPCDispConvert::COMToJS(ccx, pDispParams->rgvarg[i], val, err))
                    goto pre_call_clean_up;
                *sp++ = val;
            }
            else
            {
                // create an 'out' object
                JSObject* out_obj = JS_NewObject(cx, nsnull, nsnull, nsnull);
                if(!out_obj)
                {
                    retval = NS_ERROR_OUT_OF_MEMORY;
                    goto pre_call_clean_up;
                }
                // We'll assume in/out
                // TODO: I'm not sure we tell out vs in/out
                OBJ_SET_PROPERTY(cx, out_obj,
                        rt->GetStringID(XPCJSRuntime::IDX_VALUE),
                        &val);
                *sp++ = OBJECT_TO_JSVAL(out_obj);
            }
        }

        readyToDoTheCall = JS_TRUE;

pre_call_clean_up:

        if(!readyToDoTheCall)
            goto done;

        // do the deed - note exceptions

        JS_ClearPendingException(cx);

        if(!JSVAL_IS_PRIMITIVE(fval))
        {
            // Lift current frame (or make new one) to include the args
            // and do the call.
            JSStackFrame *fp, *oldfp, frame;
            jsval *oldsp;

            fp = oldfp = cx->fp;
            if(!fp)
            {
                memset(&frame, 0, sizeof(frame));
                cx->fp = fp = &frame;
            }
            oldsp = fp->sp;
            fp->sp = sp;

            success = js_Invoke(cx, argc, JSINVOKE_INTERNAL);

            result = fp->sp[-1];
            fp->sp = oldsp;
            if(oldfp != fp)
                cx->fp = oldfp;
        }
        else
        {
            // The property was not an object so can't be a function.
            // Let's build and 'throw' an exception.

            static const nsresult code =
                    NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED;
            static const char format[] = "%s \"%s\"";
            const char * msg;
            char* sz = nsnull;

            if(nsXPCException::NameAndFormatForNSResult(code, nsnull, &msg) && msg)
                sz = JS_smprintf(format, msg, name);

            nsCOMPtr<nsIException> e;

            XPCConvert::ConstructException(code, sz, "IDispatch", name.get(),
                                           nsnull, getter_AddRefs(e));
            xpcc->SetException(e);
            if(sz)
                JS_smprintf_free(sz);
        }

        if (!success)
        {
            retval = nsXPCWrappedJSClass::CheckForException(ccx, name.get(), "IDispatch");
            goto done;
        }

        ccx.GetThreadData()->SetException(nsnull); // XXX necessary?

        // convert out args and result
        // NOTE: this is the total number of native params, not just the args
        // Convert independent params only.
        // When we later convert the dependent params (if any) we will know that
        // the params upon which they depend will have already been converted -
        // regardless of ordering.

        outConversionFailedIndex = paramCount;
        foundDependentParam = JS_FALSE;
        if(JSVAL_IS_VOID(result) || XPCDispConvert::JSToCOM(ccx, result, *pVarResult, err))
        {
            for(i = 0; i < paramCount; i++)
            {
                jsval val;
                if(JSVAL_IS_PRIMITIVE(stackbase[i+2]) ||
                        !OBJ_GET_PROPERTY(cx, JSVAL_TO_OBJECT(stackbase[i+2]),
                            rt->GetStringID(XPCJSRuntime::IDX_VALUE),
                            &val))
                {
                    outConversionFailedIndex = i;
                    break;
                }

            }
        }

        if(outConversionFailedIndex != paramCount)
        {
            // We didn't manage all the result conversions!
            // We have to cleanup any junk that *did* get converted.

            for(PRUint32 index = 0; index < outConversionFailedIndex; index++)
            {
                if((pDispParams->rgvarg[index].vt & VT_BYREF) != 0)
                {
                    VariantClear(pDispParams->rgvarg + i);
                }
            }
        }
        else
        {
            // set to whatever the JS code might have set as the result
            retval = pending_result;
        }

done:
        if(sp)
            js_FreeStack(cx, mark);

        // TODO: I think we may need to translate this error, 
        // for now we'll pass through
        return retval;
    }
    return S_OK;
}

Here is the call graph for this function:

STDMETHODIMP XPCDispatchTearOff::QueryInterface ( REFIID  IID,
void **  pPtr 
)

QueryInterface that returns us or the main object See MSDN for form information.

Parameters:
IIDinterface ID we're querying to
pPtra pointer to the pointer that will receive the resultant interface pointer
Returns:
HRESULT

Definition at line 170 of file XPCDispTearOff.cpp.

{
    if(IsEqualIID(guid, IID_IDispatch))
    {
        *pPtr = NS_STATIC_CAST(IDispatch*,this);
        NS_ADDREF_THIS();
        return NS_OK;
    }

    if(IsEqualIID(guid, IID_ISupportErrorInfo))
    {
        *pPtr = NS_STATIC_CAST(IDispatch*,this);
        NS_ADDREF_THIS();
        return NS_OK;
    }

    return mWrappedJS->QueryInterface(XPCDispIID2nsIID(guid), pPtr);
}

Here is the call graph for this function:

Thread safe AddRef.

Thread safe Release.


Member Data Documentation

Definition at line 669 of file XPCDispPrivate.h.

Definition at line 671 of file XPCDispPrivate.h.

Definition at line 667 of file XPCDispPrivate.h.

Definition at line 678 of file XPCDispPrivate.h.


The documentation for this class was generated from the following files: