Back to index

lightning-sunbird  0.9+nobinonly
Public Types | Static Public Member Functions
XPCDispObject Class Reference

Used to invoke IDispatch methods This has turned into kind of a catch all, and probably should be cleaned up. More...

#include <XPCDispPrivate.h>

List of all members.

Public Types

enum  CallMode { CALL_METHOD, CALL_GETTER, CALL_SETTER }

Static Public Member Functions

static JSBool Dispatch (XPCCallContext &ccx, IDispatch *pDisp, DISPID dispID, CallMode mode, XPCDispParams *params, jsval *retval, XPCDispInterface::Member *member=nsnull, XPCJSRuntime *rt=nsnull)
 This invokes an IDispatch method.
static JSBool Invoke (XPCCallContext &ccx, CallMode mode)
 Used to invoke an IDispatch method using the XPCCallContext.
static HRESULT SecurityCheck (XPCCallContext &ccx, const CLSID &aCID, IDispatch **createdObject=nsnull)
 Performs the various security checks, caps, hosting flags, etc.
static HRESULT COMCreateInstance (XPCCallContext &ccx, BSTR className, PRBool enforceSecurity, IDispatch **result)
 Instantiates a COM object given a class ID or a prog ID.
static PRBool WrapIDispatch (IDispatch *pDispatch, XPCCallContext &ccx, JSObject *obj, jsval *rval)
 Wraps an IDispatch interface, returning the object as a jsval.

Detailed Description

Used to invoke IDispatch methods This has turned into kind of a catch all, and probably should be cleaned up.

Definition at line 1063 of file XPCDispPrivate.h.


Member Enumeration Documentation

Enumerator:
CALL_METHOD 
CALL_GETTER 
CALL_SETTER 

Definition at line 1066 of file XPCDispPrivate.h.


Member Function Documentation

HRESULT XPCDispObject::COMCreateInstance ( XPCCallContext ccx,
BSTR  className,
PRBool  enforceSecurity,
IDispatch **  result 
) [static]

Instantiates a COM object given a class ID or a prog ID.

Parameters:
ccxan XPConnect call context
classNamea prog ID or a class ID in the form of {00000000-0000-0000-0000-000000000000}
enforceSecurityif true, will apply checks to ensure the object can be created giving the current security settings.
resultpointer to the pointer to receive the interface pointer

Definition at line 137 of file XPCDispObject.cpp.

{
    NS_ENSURE_ARG_POINTER(result);
    // Turn the string into a CLSID
    _bstr_t bstrName(className);
    CLSID classID = CLSID_NULL;
    HRESULT hr = CLSIDFromString(bstrName, &classID);
    if(FAILED(hr))
        hr = CLSIDFromProgID(bstrName, &classID);
    if(FAILED(hr) || ::IsEqualCLSID(classID, CLSID_NULL))
        return hr;
    
    // If the caller cares about security do the necessary checks
    // This results in the object being instantiated, so we'll use
    // it
    if(enforceSecurity)
        return SecurityCheck(ccx, classID, result);
    
    CComPtr<IDispatch> disp;
    hr = disp.CoCreateInstance(classID);
    if(FAILED(hr))
        return hr;

    disp.CopyTo(result);

    return S_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool XPCDispObject::Dispatch ( XPCCallContext ccx,
IDispatch pDisp,
DISPID  dispID,
CallMode  mode,
XPCDispParams params,
jsval retval,
XPCDispInterface::Member member = nsnull,
XPCJSRuntime rt = nsnull 
) [static]

This invokes an IDispatch method.

Parameters:
ccxan XPConnect call context
pDispthe IDispatch pointer
dispIDthe DISPID of the method/property
modethe call mode, method/property
paramsthe parameters need for the method/property
retvalpointer to a jsval to receive the return value
membera pointer to an interface member
rta pointer to the XPConnect JS Runtime
Returns:
true if the method/property was invoked properly

Definition at line 168 of file XPCDispObject.cpp.

{
    _variant_t dispResult;
    jsval val;
    uintN err;
    uintN argc = params->GetParamCount();
    // Figure out what we're doing (getter/setter/method)
    WORD dispFlags;
    if(mode == CALL_SETTER)
    {
        dispFlags = DISPATCH_PROPERTYPUT;
    }
    else if(mode == CALL_GETTER)
    {
        dispFlags = DISPATCH_PROPERTYGET;
    }
    else
    {
        dispFlags = DISPATCH_METHOD;
    }
    HRESULT invokeResult;
    EXCEPINFO exception;
    // Scope the lock
    {
        // avoid deadlock in case the native method blocks somehow
        AutoJSSuspendRequest req(ccx);  // scoped suspend of request
        // call IDispatch's invoke
        invokeResult= disp->Invoke(
            dispID,                  // IDispatch ID
            IID_NULL,                // Reserved must be IID_NULL
            LOCALE_SYSTEM_DEFAULT,   // The locale context, use the system's
            dispFlags,               // Type of Invoke call
            params->GetDispParams(), // Parameters
            &dispResult,             // Where the result is stored
            &exception,              // Exception information
            0);                      // Index of an argument error
    }
    if(SUCCEEDED(invokeResult))
    {
        *retval = JSVAL_VOID;
        if(mode == CALL_METHOD)
        {
            NS_ASSERTION(member, "member must not be null if this is a method");
            for(PRUint32 index = 0; index < argc; ++index)
            {
                const XPCDispInterface::Member::ParamInfo & paramInfo = member->GetParamInfo(index);
                if(paramInfo.IsOut())
                {
                    if(!XPCDispConvert::COMToJS(ccx, params->GetParamRef(index), val, err))
                        return ThrowBadParam(err, index, ccx);

                    if(paramInfo.IsRetVal())
                    {
                        *retval = val;
                    }
                    else
                    {
                        jsval * argv = ccx.GetArgv();
                        // Out, in/out parameters must be objects
                        if(!JSVAL_IS_OBJECT(argv[index]) ||
                            !OBJ_SET_PROPERTY(ccx, JSVAL_TO_OBJECT(argv[index]),
                                rt->GetStringID(XPCJSRuntime::IDX_VALUE), &val))
                            return ThrowBadParam(NS_ERROR_XPC_CANT_SET_OUT_VAL, index, ccx);
                    }
                }
            }
        }
        if(dispResult.vt != VT_EMPTY)
        {
            if(!XPCDispConvert::COMToJS(ccx, dispResult, val, err))
            {
                ThrowBadParam(err, 0, ccx);
            }
            *retval = val;
        }
    }
    // Set the result and throw the error if one occured
    ccx.GetXPCContext()->SetLastResult(invokeResult);

    if(NS_FAILED(invokeResult))
    {
        XPCThrower::ThrowCOMError(ccx, invokeResult, NS_ERROR_XPC_COM_ERROR, 
                                  invokeResult == DISP_E_EXCEPTION ? 
                                      &exception : nsnull);
        return JS_FALSE;
    }
    return JS_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool XPCDispObject::Invoke ( XPCCallContext ccx,
CallMode  mode 
) [static]

Used to invoke an IDispatch method using the XPCCallContext.

Parameters:
ccxan XPConnect call context
modecall mode for the call

Definition at line 262 of file XPCDispObject.cpp.

{
    nsresult rv = ccx.CanCallNow();
    if(NS_FAILED(rv))
    {
        // If the security manager is complaining then this is not really an
        // internal error in xpconnect. So, no reason to botch the assertion.
        NS_ASSERTION(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO, 
                     "hmm? CanCallNow failed in XPCDispObject::Invoke. "
                     "We are finding out about this late!");
        XPCThrower::Throw(rv, ccx);
        return JS_FALSE;
    }

    // TODO: Remove type cast and change GetIDispatchMember to use the correct type
    XPCDispInterface::Member* member = NS_REINTERPRET_CAST(XPCDispInterface::Member*,ccx.GetIDispatchMember());
    XPCJSRuntime* rt = ccx.GetRuntime();
    XPCContext* xpcc = ccx.GetXPCContext();
    XPCPerThreadData* tls = ccx.GetThreadData();
    
    jsval* argv = ccx.GetArgv();
    uintN argc = ccx.GetArgc();

    tls->SetException(nsnull);
    xpcc->SetLastResult(NS_ERROR_UNEXPECTED);

    // set up the method index and do the security check if needed

    PRUint32 secFlag;
    PRUint32 secAction;

    switch(mode)
    {
        case CALL_METHOD:
            secFlag   = nsIXPCSecurityManager::HOOK_CALL_METHOD;
            secAction = nsIXPCSecurityManager::ACCESS_CALL_METHOD;
            break;
        case CALL_GETTER:
            secFlag   = nsIXPCSecurityManager::HOOK_GET_PROPERTY;
            secAction = nsIXPCSecurityManager::ACCESS_GET_PROPERTY;
            break;
        case CALL_SETTER:
            secFlag   = nsIXPCSecurityManager::HOOK_SET_PROPERTY;
            secAction = nsIXPCSecurityManager::ACCESS_SET_PROPERTY;
            break;
        default:
            NS_ASSERTION(0,"bad value");
            return JS_FALSE;
    }
    jsval name = member->GetName();

    nsIXPCSecurityManager* sm = xpcc->GetAppropriateSecurityManager(secFlag);
    XPCWrappedNative* wrapper = ccx.GetWrapper();
    if(sm && NS_FAILED(sm->CanAccess(secAction, &ccx, ccx,
                                     ccx.GetFlattenedJSObject(),
                                     wrapper->GetIdentityObject(),
                                     wrapper->GetClassInfo(), name,
                                     wrapper->GetSecurityInfoAddr())))
    {
        // the security manager vetoed. It should have set an exception.
        return JS_FALSE;
    }

    IDispatch * pObj = NS_REINTERPRET_CAST(IDispatch*,
                                            ccx.GetTearOff()->GetNative());
    PRUint32 args = member->GetParamCount();
    uintN err;
    // Make sure setter has one argument
    if(mode == CALL_SETTER)
        args = 1;
    // Allow for optional parameters. We'll let COM handle the error if there
    // are not enough parameters
    if(argc < args)
        args = argc;
    XPCDispParams * params = new XPCDispParams(args);
    jsval val;
    // If this is a setter, we just need to convert the first parameter
    if(mode == CALL_SETTER)
    {
        params->SetNamedPropID();
        if(!XPCDispConvert::JSToCOM(ccx, argv[0], params->GetParamRef(0), err))
        {
            delete params;
            return ThrowBadParam(err, 0, ccx);
        }
    }
    else if(mode != CALL_GETTER)    // This is a function
    {
        // Convert the arguments to the function
        for(PRUint32 index = 0; index < args; ++index)
        {
            const XPCDispInterface::Member::ParamInfo & paramInfo = member->GetParamInfo(index);
            if(paramInfo.IsIn())
            {
                val = argv[index];
                if(paramInfo.IsOut())
                {
                    if(JSVAL_IS_PRIMITIVE(val) ||
                        !OBJ_GET_PROPERTY(ccx, JSVAL_TO_OBJECT(val),
                                          rt->GetStringID(XPCJSRuntime::IDX_VALUE),
                                          &val))
                    {
                        delete params;
                        return ThrowBadParam(NS_ERROR_XPC_NEED_OUT_OBJECT, index, ccx);
                    }
                    paramInfo.InitializeOutputParam(params->GetOutputBuffer(index), params->GetParamRef(index));
                }
                if(!XPCDispConvert::JSToCOM(ccx, val, params->GetParamRef(index), err, paramInfo.IsOut()))
                {
                    delete params;
                    return ThrowBadParam(err, index, ccx);
                }
            }
            else
            {
                paramInfo.InitializeOutputParam(params->GetOutputBuffer(index), params->GetParamRef(index));
            }
        }
    }
    // If this is a parameterized property
    if(member->IsParameterizedProperty())
    {
        // We need to get a parameterized property object to return to JS
        // NewInstance takes ownership of params
        if(XPCDispParamPropJSClass::NewInstance(ccx, wrapper,
                                                member->GetDispID(),
                                                params, &val))
        {
            ccx.SetRetVal(val);
            if(!JS_IdToValue(ccx, 1, &val))
            {
                // This shouldn't fail
                NS_ERROR("JS_IdToValue failed in XPCDispParamPropJSClass::NewInstance");
                return JS_FALSE;
            }
            JS_SetCallReturnValue2(ccx, val);
            return JS_TRUE;
        }
        // NewInstance would only fail if there was an out of memory problem
        JS_ReportOutOfMemory(ccx);
        delete params;
        return JS_FALSE;
    }
    JSBool retval = Dispatch(ccx, pObj, member->GetDispID(), mode, params, &val, member, rt);
    if(retval && mode == CALL_SETTER)
    {
        ccx.SetRetVal(argv[0]);
    }
    else
    {
        ccx.SetRetVal(val);
    }
    delete params;
    return retval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

HRESULT XPCDispObject::SecurityCheck ( XPCCallContext ccx,
const CLSID &  aCID,
IDispatch **  createdObject = nsnull 
) [static]

Performs the various security checks, caps, hosting flags, etc.

Instantiates the object and will return that object if createdObject result is not null

Parameters:
ccxan XPConnect call context
aCIDthe class ID to be tested
createdObjectis the optional object to be returned

Definition at line 76 of file XPCDispObject.cpp.

{
    nsresult rv;
    nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID, &rv);
    if(NS_FAILED(rv)) return E_UNEXPECTED;

    PRUint32 hostingFlags = nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_NOTHING;
    dispSupport->GetHostingFlags(nsnull, &hostingFlags);
    PRBool allowSafeObjects;
    if(hostingFlags & (nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_SAFE_OBJECTS))
        allowSafeObjects = PR_TRUE;
    else
        allowSafeObjects = PR_FALSE;
    PRBool allowAnyObjects;
    if(hostingFlags & (nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_ALL_OBJECTS))
        allowAnyObjects = PR_TRUE;
    else
        allowAnyObjects = PR_FALSE;
    if(!allowSafeObjects && !allowAnyObjects)
        return E_FAIL;

    PRBool classExists = PR_FALSE;
    PRBool ok = PR_FALSE;
    const nsCID & ourCID = XPCDispCLSID2nsCID(aCID);
    dispSupport->IsClassSafeToHost(ccx, ourCID, PR_FALSE, &classExists, &ok);
    if(classExists && !ok)
        return E_FAIL;

    // Test if the object is scriptable
    PRBool isScriptable = PR_FALSE;
    if(!allowAnyObjects)
    {
        PRBool classExists = PR_FALSE;
        dispSupport->IsClassMarkedSafeForScripting(ourCID, &classExists, &isScriptable);
        if(!classExists)
            return REGDB_E_CLASSNOTREG;
    }

    // Create the object
    CComPtr<IDispatch> disp;
    // If createdObject isn't null we need to create the object
    if (createdObject)
    {
        HRESULT hr = disp.CoCreateInstance(aCID);
        if(FAILED(hr))
            return hr;
        // if we don't allow just any object, and it wasn't marked 
        // safe for scripting then ask the object (MS idea of security)
        if (!allowAnyObjects && !isScriptable)
        {
            dispSupport->IsObjectSafeForScripting(disp, NSID_IDISPATCH, &isScriptable);
            if(!isScriptable)
                return E_FAIL;
        }
        disp.CopyTo(createdObject);
    }

    return S_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool XPCDispObject::WrapIDispatch ( IDispatch pDispatch,
XPCCallContext ccx,
JSObject obj,
jsval rval 
) [static]

Wraps an IDispatch interface, returning the object as a jsval.

Parameters:
pDispatchIDispatch pointer
cxa JS Context
objA pointer to a JS object serving as the global object
rvalis a pointer to a jsval to receive the JS object wrapper

Definition at line 52 of file XPCDispObject.cpp.

{
    if(!pDispatch)
    {
        return PR_FALSE;
    }

    // Wrap the desired COM object
    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
    nsresult rv = ccx.GetXPConnect()->WrapNative(
        ccx, obj, NS_REINTERPRET_CAST(nsISupports*, pDispatch), NSID_IDISPATCH,
        getter_AddRefs(holder));
    if(NS_FAILED(rv) || !holder)
    {
        return PR_FALSE;
    }
    JSObject * jsobj;
    if(NS_FAILED(holder->GetJSObject(&jsobj)))
        return PR_FALSE;
    *rval = OBJECT_TO_JSVAL(jsobj);
    return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:


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