• Advertisement
Sign in to follow this  

Problem: Attempting to pass around a void* as a handle within Angelscript.

This topic is 1673 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

The Problem

I've attempted to register an object method ( asEngine_RegisterObjectMethod ) that takes in a GlobalData* and a uint, than returns a ref type.  Something about returning the ref however seems to cause the function to pass in an invalid pointer as the first parameter.  Modifying the function to return a non-generic type seems to correct the problem.


What I am trying to do -- Bigger Picture

I want to retrieve some data in the form of a void* and easily pass it around to various other bound functions.

In this simple example I want to retrieve a void* from an object as a generic handle, cast that handle, than pass that handle to another C-style function.


I want to able to return a void* as a ref ( or ref@, not sure since ref seems to be a special case), then cast that to a Entity@ and pass it along to a registered function that can take an Entity*.


I'd also like to avoid needing the user to register a cast function if they don't need to.  It seems like CScriptHandle can already be casted from one handle type to another.


This is ideally how I want the angelscript to look when the user attempts to get/pass around the data.

GLOBALDATA@ GlobalData = GetGlobalData();
ENTITY@ Entity = cast<ENTITY>(GlobalData.GetData( 2 ));
if( Entity !is null ){
    Entity_ProcessEntity( Entity );

I have registered the CScriptHandle type with the asEngine, however I seem to be missing something important during the implementation as things are not working as expected.


This is what the simplified C++ modules look like.

static class GlobalData
   void* GetData( uint index ){ return _data[index]; }

   void** _data[10];
} GlobalDataInstance;

//C-Style interface for GlobalData
GlobalData* GlobalData_GetGlobalData( void ){
    return &GlobalDataInstance;

void* GlobalData_GetData( GlobalData* globalData, uint index ){
   return globalData->GetData(index);

void Entity_ProcessEntity( Entity* entity ){

This is how they are registered with asEngine

Result = asEngine_RegisterGlobalFunction( Engine, "GLOBALDATA@ GetGlobalData()", asFUNCTION_t( &GlobalData_GetGlobalData), asCALL_CDECL );
Result = asEngine_RegisterObjectType( Engine, "GLOBALDATA", 0, asOBJ_REF | asOBJ_NOCOUNT );
Result = asEngine_RegisterObjectMethod( Engine, "GLOBALDATA",   "ref GetData( uint Index) const",  asFUNCTION_t(&GlobalData_GetData), asCALL_CDECL_OBJFIRST );

Result = asEngine_RegisterGlobalFunction( Engine, "void Entity_ProcessEntity( ENTITY@ entity)", asFUNCTION_t( &Entity_ProcessEntity), asCALL_CDECL );

asEngine_RegisterObjectMethod( Engine, "GLOBALDATA",   "ref GetData( uint Index) const",  asFUNCTION_t(&GlobalData_GetData), asCALL_CDECL_OBJFIRST );
This seems to be where the problem is occuring.  The GlobalData* provided here is not valid.  It is not null, however it is not GlobalDataInstance.


It could be that CScriptHandle is not the right solution for what i want to do, which is why I've included all of the additional information.



Share this post

Link to post
Share on other sites

CScriptHandle is a C++ class and not a simple pointer. When you tell AngelScript that a function returns a "ref", then AngelScript will expect to receive a valid CScriptHandle object, but in your case you're just returning a void*. The calling convention for returning an object by value is different from the calling convention for returning a pointer. In the former a hidden pointer to a memory buffer is passed as the first argument to the function. This is why you see an invalid pointer.


If you want to use a completely generic pointer like void* in C/C++, then it would be best for you to register void* as a type itself. Then you can register your functions that take and receive void* using this type:


asEngine_RegisterObjectType(engine, "void_ptr", sizeof(void*), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE);
asEngine_RegisterObjectMethod( Engine, "GLOBALDATA",   "void_ptr GetData( uint Index) const",  asFUNCTION_t(&GlobalData_GetData), asCALL_CDECL_OBJFIRST );


As for casting the void_ptr into valid handles; I think it is best for you to create an appropriate function for this. If you do not want to have one function for each possible cast type, then I suggest you implement a function that takes a variable argument type, similar to the CScriptAny::Retrieve method. The problem is that the void* doesn't carry any information about the type of the object it points to, so I have no idea how you plan on validating if the cast is valid or not.

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement