Sign in to follow this  
kunitoki

how to use properly GetMethodIdByXXX ?

Recommended Posts

i'm trying to call a method of a scripted class from within a c function. i don't know how to use these cool functions. i mean, i don't know if i have to pass a object name (from the docs is stated as class name, but sure it isn't) that is already been declared. the script is doing: class Component { void mouseDown(int x, int y) { // do something } }; Component c; the c++ counterpart is trying to (after compiling the script bounded with no module): int onMouseDownID = eng->GetMethodIDByDecl(0, "c", "void mouseDown(int,int)" ); if (onMouseDownID >= 0) { con->Prepare(onMouseDownID); con->SetArgDWord(0, e.x); con->SetArgDWord(1, e.y); con->Execute(); } but i still get onMouseDownID == -12... i've tried to change "c" with "Component" as one should learn from the docs... but obviously nothing happens. anyway the script is correctly compiling and executing a previously declared main function, and the context isn't released after main execution. maybe i have to take into account the script section name ? or i have to move the "c" allocation (in script) to a function that i have to call after ?

Share this post


Link to post
Share on other sites
ok now i have understood that i was mistaking. indeed GetMethodIDByXXX should have a class name not a declared object name to function properly. anyway i'm able to get the correct id for the function, prepare it and execute but it seems that the body of my scripted function is never reached. anyway i'm getting a asEXECUTION_ABORTED every time i call the method.

Share this post


Link to post
Share on other sites
i think i got it now:

void* executedObject = eng->GetGlobalVarPointer(eng->GetGlobalVarIDByName(0,"c"));
int onMouseDownID = eng->GetMethodIDByDecl(0, "Component", "void mouseDown(int,int)" );
if (onMouseDownID >= 0 && executedObject != 0)
{
asIScriptContext* con = eng->CreateContext();
con->Prepare(onMouseDownID);
con->SetObject(executedObject);
con->SetArgDWord(0, e.x);
con->SetArgDWord(1, e.y);

int r = con->Execute();
if( r != asEXECUTION_FINISHED )
{
// The execution didn't finish as we had planned. Determine why.
String errorString;
if( asEXECUTION_ABORTED )
errorString = T("The script has timed out.");
else if( asEXECUTION_EXCEPTION )
{
errorString = T("The script ended with an exception.\n");
}
else
errorString = T("The script ended for some unforeseen reason.");

eng->reportCompilerErrors(errorString);
}

con->Release();
}

this one is working, so the method "mouseDown" declared in script is called bound to a object declared globally as "c". the only thing is that i'm creating a context every time the block is called. and when i reach con->Release() i get some memory exceptions cause that Release() call is also deleting its internal asCScriptEngine, because i see that context is holdingRef the engine itself. any advice ? i've looked into the event example but it seems that i can't recreate it anymore...

Share this post


Link to post
Share on other sites
I think I'll have to clarify the documentation here, and also change the name of the parameter from 'object' to 'classname', or something like that. That should cause less confusion in regards to the use of this method.

I also need to make some tests with regards to the memory exceptions with context->Release(). This should not happen, and you're not doing anything wrong that I can see, so it is possible that there is a bug there.

There are a couple of errors in your code, where you're verifying the return code from Execute(). You're not actually r with asEXECUTION_ABORTED and asEXECUTION_EXCEPTION, so if the code is not asEXECUTION_FINISHED, your code will always report it as asEXECUTION_ABORTED. (You got this code from the tutorial, didn't you? I had this same bug there before it was discovered by SiCrane a while back [wink])

In addition to that, the function id for the onMouseDownID only has to be obtained once after compiling the script. It will stay the same until the script is recompiled. The script context can also be reused between calls if you want.

Regards,
Andreas

Share this post


Link to post
Share on other sites
ok andreas, thanx for the tips. i'll sure try something for optimize a bit that piece. ah, the problem with the wrong check on return result, i was expecting something like this, altought the excerpt runs the compiled script with no problems at all. would a simple loop calling execute method till is not asEXECUTION_FINISHED (breaking if error or timeout) would do ? or is better that i put in the line callback and stick a 10ms suspend state ? could be this treated as a typical pseudo loop for controlling script execution (after have setup a line callback that suspend the script if the timeout have been reached?

context->Prepare()

for(;;)
{
timeout = getCurrentMillis() + 10; // 10ms runs
r = context->Execute();

if (r == asEXECUTION_FINISHED)
break;
else if (r == asEXECUTION_SUSPENDED)
// what to do here ?
else if (r == asEXECUTION_ABORTED)
reportAbortToUser();
break;
else if (r == asEXECUTION_EXCEPTION)
reportErrorToUser();
break;
}

context->release() // should i do this here if i have to reuse the context ?

Share this post


Link to post
Share on other sites
anyway i've investigated a bit. and it seems that the reference counting for the objects is still good. the problem arises when i try to release the second context i've created and executed with the function i'm trying to get from the script. the line that is offending is

for( asUINT n = 0; n < stackBlocks.GetLength(); n++ )
{
if( stackBlocks[n] )
delete[] stackBlocks[n];
}
stackBlocks.SetLength(0);

there 1 stackBlock left out (as i can see from local variables in debugger), but when it triggers the delete[] it got an int 3 after a couple of ntdll calls..
i thought maybe i was releasing the context without checking if the execution has finished, and that's causeing the problem, but i see from the release code of angelscript's context that we are aborting it before killing itself. so maybe that's not the point.

Share this post


Link to post
Share on other sites
The execution loop looks good for executing scripts that return control to the application every once in a while.

When you call Release() on the context, you shouldn't use that particular reference anymore. Thus if you intend to reuse the context you shouldn't call Release().

The problem with the stackBlocks will be difficult to find as I've not been able to reproduce it. Would it be possible for you to narrow down your application to a small test app that reproduces the problem, and then send it to me so that I can debug it? I'll do my best to figure out what's happening though.

Regards,
Andreas

Share this post


Link to post
Share on other sites
yeah for sure. but now i have no time, maybe this evening (here is 18.30 eheh)... do you mean that i have to send you the project or a debug build executable ? for the latter ok, the first, is something like 20 mb uncompressed sourcecode... (plus projects, file documentation and such you can't be under 11mb zipped).

thanx however man... you really really kind ;)

Share this post


Link to post
Share on other sites
Well, the ideal would be for you to make a small project that does nothing else than reproducing the problem. I'd prefer not to have to go through your entire project to find this small problem.

The debug executable without the project won't be of much use as I need to the source code in order to discover the cause.

If you can't recreate the problem in a smaller project, no problem. I'll eventually find the bug anyway (if it really is a bug in the library), though you'll have to be patient.

Share this post


Link to post
Share on other sites
actually i've found where is the problem actually, but dunnow how deep in the library it is.
if i run this from c++ is fine, so no problems in releasing the context:


asIScriptContext* eventContext = scriptEngine->CreateContext();

int methodID = scriptEngine->GetMethodIDByDecl(0,"Object","void mouseDown()");
void* methodOwner = scriptEngine->GetGlobalVarPointer( scriptEngine->GetGlobalVarIDByName(0,"c"));

if (methodID >= 0 && methodOwner != 0)
{
eventContext->Prepare(methodID);
eventContext->SetObject(methodOwner);
eventContext->Execute();
}

eventContext->Release();


but if i try to call something like this:


asIScriptContext* eventContext = scriptEngine->CreateContext();

int methodID = scriptEngine->GetMethodIDByDecl(0,"Object","void mouseDown(int,int)");
void* methodOwner = scriptEngine->GetGlobalVarPointer( scriptEngine->GetGlobalVarIDByName(0,"c"));

if (methodID >= 0 && methodOwner != 0)
{
int x = 100, y = 200;

eventContext->Prepare(methodID);
eventContext->SetObject(methodOwner);
eventContext->SetArgDWord(0, x);
eventContext->SetArgDWord(1, y);

eventContext->Execute();
}

eventContext->Release();


now when i delete the context, exceptions arise.
anyway in both cases the script bound methods are called correctly.


[Edited by - kunitoki on April 7, 2006 8:30:28 AM]

Share this post


Link to post
Share on other sites
Seems to be a buffer overflow within the library. I'm glad you managed to narrow the problem down to this, as it would have been very difficult to find otherwise.

I'll make some tests and fix whatever bug I find. I'll let you know as soon as it's done.

Regards,
Andreas

Share this post


Link to post
Share on other sites
I found the problem. I had forgotten to add parenthesis around a ?: operator. This caused the stackFramePointer to be invalid, which in turn caused the buffer overflow in the SetArgDWord() methods.

Line 286 in file as_context.cpp, function Prepare(), should be:


argumentsSize = currentFunction->GetSpaceNeededForArguments() + (currentFunction->objectType ? PTR_SIZE : 0);


Thanks for helping me with this bug. [smile]

I'm updating the SVN on SourceForge.net right now.

Regards,
Andreas

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this