Create new AS objects and calling methods from C++

Kelkar, Anand akelkar at ea.com
Tue Jun 24 09:31:36 PDT 2008


Hey All,

 

Just wanted to report back to the my findings about how I ended up
creating new AS objects from C++  and calling methods on newly created
scriptObjects from C++. 

 

I want to know from the experts on the list here whether my approach is
correct or not?  If this seems to be correct then I am going to start
building a framework around this approach that can be used inside my
application.

 

I tried hard to use topLevel->callproperty function to call a method but
was not able to use it because of mismatching namespaces.

 

In AS code I have this

// This defines a ObjectFactory class that can create new object
instances of classes.

// this file gets included inside flash9classes.as. 

 

package 

{

 

    import avmplus.Domain;

 

    // this is just a trial class.    

    class PlayerEntity extends Object

    {

        public function PlayerEntity():void

        {

            trace("PlayerEntity constructor");

        }

 

        public function PlayerMove():void

        {

            trace("PlayerEntity::PlayerMove() " );

        }

 

    }

 

    // This class allows to create/instantiate object instances of class

    class ObjectFactory extends Object

    {

        public function ObjectFactory():void

        {

            trace("ObjectFactory Created");

        }

        

        // instanceName is ignored at the moment.

        public function  CreateObject(className:String,
instanceName:String):Object

        {

            trace("Creating new object of type " + className + " with
instance " + instanceName);

 

            var classType:Class =
Domain.currentDomain.getClass(className);

            

            trace("classType = " +
Domain.currentDomain.getClass(className));

            

            var newObject:Object = applyConstructor0(classType);

 

            return newObject;

         }

        

        

        // this actually creates a new instance of the class

        public function applyConstructor0(cls:Class):*

        {

            return new cls();

        }

 

    

    }

 

    // create a global variable which is accessed thru
avmshell::InstantiateNewObjectRaw function

    public var globalFactory:ObjectFactory = new ObjectFactory();

 

}

 

Then in C++

 

// this is a sample implementation of how we can instantiate a new
object of a given class. Mostly copied from ActiveScript.cpp

Atom Shell::InstantiateNewObjectRaw(const char *name, va_list va)

{

    static const int maxAtoms = 64;

    Atom args[maxAtoms];

 

    Atom objectFactory = NULL;

 

    // Get the AS object named 'objectFactory' from factory.as that is
already loaded by shell.

    DomainEnv *domEnv = mToplevel ? mToplevel->domainEnv() : NULL;

    if (!domEnv) {

        AvmDebugMsg(false, "InstantiateNewObjectRaw('%s') - early exit
due to null core/toplevel/domainEnv\r\n", name);

        return NULL;

    }

    Multiname multiname(publicNamespace,
constantString("globalFactory"));

    ScriptEnv *se = (ScriptEnv *)domEnv->getScriptInit(&multiname);

    if (!se || !se->global) {

        AvmDebugMsg(true, "InstantiateNewObjectRaw('%s') - early exit
due to no ScriptEnv\r\n", name);

        return E_FAIL;

    }

 

    objectFactory = mToplevel->getproperty(se->global->atom(),
&multiname, mToplevel->toVTable(se->global->atom()));

 

    // get the function from the object.

    Multiname multiname_co(publicNamespace,
constantString("CreateObject"));

    Atom ani = mToplevel->getproperty(objectFactory, &multiname_co,
mToplevel->toVTable(objectFactory));

    if (!isObject(ani)) {

        AvmDebugMsg(true, "objectFactory('%s') - no property\r\n");

        return E_FAIL;

    }

    // prepare the args

    int argc = 2;

    args[0] = objectFactory;

    Stringp className = newString(name);

    args[1] = className->toAtom();

    Atom arg = va_arg (va, Atom);

    while (arg != (Atom)-1) {

        args[argc] = arg;

        argc++;

        arg = va_arg (va, Atom);

        AvmAssert(argc<maxAtoms);

    }

    // Now call the method.

    AvmDebugMsg(false, "Calling objectFactory::%s\r\n", name);

    Atom ret = AvmCore::atomToScriptObject(ani)->call(argc-1, args);

 

    return ret;

}

 

 

// this function allows to call a method on already created instance
object.

Atom Shell::CallMethod(Atom instanceObj, char * methodName, ...)

{

    Atom ret = NULL;

    static const int maxAtoms = 64;

    Atom args[maxAtoms];

 

    ScriptObject * instanceObject = atomToScriptObject(instanceObj) ;

    AvmAssert(instanceObject != NULL);

 

    va_list va;

    va_start (va, methodName); 

 

    // fetch the function from the object.

 

    Multiname multinameMethodName(publicNamespace,
constantString(methodName));

 

    // prepare the args

    // this = argv[0] (ignored)

    // arg1 = argv[1]

    // argN = argv[argc]

 

    int argc = 1;

    args[0] = NULL;

    Atom arg = va_arg (va, Atom);

    while (arg != (Atom)-1) 

    {

        args[argc] = arg;

        argc++;

        arg = va_arg (va, Atom);

        AvmAssert(argc<maxAtoms);

    }

    va_end(va);

 

    // after trying unsuccessful ways to match the namespace of method
defined inside scriptobject with 

    // namespace in the multiname that is getting created above finally
I came to conclusion we can just 

    // use getName function in Traits to find matching Binding for the
method.

 

    Traits * pTraits = instanceObject->traits();

    Binding b = pTraits->getName(constantString(methodName));

 

    // following code is copied from TopLevel->callproperty function

    switch (b&7)

    {

    case BIND_METHOD:

        {

            // force receiver == base.  if caller used OP_callproplex
then receiver was null.

            args[0] = instanceObj;

            MethodEnv* method =
mToplevel->toVTable(instanceObj)->methods[AvmCore::bindingToMethodId(b)]
;

            AvmAssert(method != NULL);

            ret =  method->coerceEnter(argc - 1, args);

        }

        break;

    }

 

 

    /*

    // this was old unsuccessful way of calling a method, method could
not be found inside ScriptObject because of 

    // unmatched namespace.

 

    // Now call the method.

    TRY(this, kCatchAction_ReportAsError)

    {

    ret = this->mToplevel->callproperty(instanceObj,
&multinameMethodName, argc - 1, args, mToplevel->toVTable(instanceObj));

    }

    CATCH(Exception * exception) 

    {

    //return handleException(exception);

    return exception->atom;

 

    }

    END_CATCH

    END_TRY

    */

 

    return ret;

 

}

 

And then in C++ application

Stringp instanceName = gpAvmShell->newString("playerEntity");

Atom playerEntInst = gpAvmShell->InstantiateNewObject("PlayerEntity",
instanceName->toAtom(), (Atom)-1);

Atom ret = gpAvmShell->CallMethod(playerEntInst, " PlayerMove",
(Atom)-1);

 

 

Thanks

Anand

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.mozilla.org/pipermail/tamarin-devel/attachments/20080624/67aeb210/attachment-0001.html 


More information about the Tamarin-devel mailing list