Advertisement

Casting UINT64 to Function

Started by October 13, 2023 08:50 AM
5 comments, last by WitchLord 1 year, 1 month ago

Hello, I'm trying to implement LoadLibrary and GetProcAddress in AngleScript.

uint64_t asLoadLibrary(string& library)
{
	return (uint64_t)LoadLibraryA(library.c_str());
}
uint64_t asGetProcAddress(uint64_t* modulePTR, string& msg)
{
	return (uint64_t)GetProcAddress((HMODULE)*modulePTR, msg.c_str());
}

This functions works great, Here's how I use it in AngleScript :

uint64 user32Module = asLoadLibrary("user32.dll");
asPrint(LogType::Default, "   > User32.dll Module 	 " + asPtrAsString(user32Module) + "\n");
uint64 messageBoxFuncAddress = asGetProcAddress(user32Module, "MessageBoxA");
asPrint(LogType::Default, "   > MessageBoxA Addr 	 " + asPtrAsString(messageBoxFuncAddress) + "\n");

Results are fine but now I don't know how to call this function dynamically, I added funcdef in global scope :

// Function Definitions
funcdef int MSGBOX(uint64, string, string, uint);

I tried to cast it but it doesn't work :

MSGBOX@ msgboxFunc = cast<MSGBOX@>(messageBoxFuncAddress);

How can I achieve this?

Also I have a side question, When passing user32Module to asGetProcAddress why modulePTR it have to be uint64_t* and not uint64_t?


Thanks

  • The universe is basically an animal. It grazes on the ordinary.

Sounds like you want object handles in AngelScript and pointers on c++, not a uint64.

You have no guarantee that the pointer is type convertible to and from an int64. We happen to be mostly on 64 bit systems today, but code like what you suggest has broken badly in various system updates through history. Pointers happen to be 64 buts on these systems but that's not the data type.

Advertisement

@frob I just want to dynamically call functions from DLLs and implement LoadLibrary.
I currently have a workaround by creating meta script system, I register new function from script and evaluate a new script from main script.

// LoadLibrary + Meta Script Test
uint64 user32Module = as_LoadLibrary("user32.dll");
as_Print(LogType::Default, "   > User32.dll Module 	 " + as_PtrAsString(user32Module) + "\n");
uint64 messageBoxFuncAddress = as_GetProcAddress(user32Module, "MessageBoxA");
as_Print(LogType::Default, "   > MessageBoxA Addr 	 " + as_PtrAsString(messageBoxFuncAddress) + "\n");
as_RegisterFunction("int Win32MessageBox(int64, cchar, cchar, int)", messageBoxFuncAddress, CallConvTypes::STDCALL);
as_EvalScript("Win32MessageBox(0, as_StringToCSTR(\"Hello From Win32 MessageBox!\"), as_StringToCSTR(\"< Meta Script >\"), 0);", "MetaScript");
  • The universe is basically an animal. It grazes on the ordinary.

I suggest you make asGetProcAddress return a CScriptHandle (represented as ‘ref’ in the script) holding the asIScriptFunction pointer, instead of returning an uint64. The asGetProcAddress should register the function with the engine to get the asIScriptFunction pointer. asGetProdAddress would of course have to receive the function signature, so it can register the function. That way the script will be able to do a cast from the returned ref to the appropriate funcdef and call the function.​

You may also want to make the asLoadLibrary a little bit safer by not returning an uint64 directly. Instead register a type to represent the library pointer, so that the scripts cannot just give any number to asGetProcAddress, and only the value actually received from asLoadLibrary. Alternatively, don't register the asLoadLibrary at all, and just embed the logic of loading the library into asGetProcAddress itself based on the name of the library.

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

@WitchLord Hey Andreas, Thank you for replying,

I toke a day and thought it out, I created a simple linker for my script engine, It's a config file look like this :

[Modules]
kernel32.dll|k32
user32.dll|u32

[Imports]
u32|MessageBoxA|STDCALL|int impMessageBoxA(int64, cchar, cchar, int)
k32|Sleep|STDCALL|int impSleep(int)

Before executing main script my app parse and translate this to :

uint64 k32 = as_LoadLibrary("kernel32.dll");
uint64 u32 = as_LoadLibrary("user32.dll");
as_ImportFunction("int impMessageBoxA(int64, cchar, cchar, int)", as_GetProcAddress(u32, "MessageBoxA"), CallConvTypes::STDCALL);
as_ImportFunction("int impSleep(int)", as_GetProcAddress(k32, "Sleep"), CallConvTypes::STDCALL);

After executing this I execute my main script. I am happy with the reason, Thank you for all the effort on this great scripting language!

  • The universe is basically an animal. It grazes on the ordinary.

Yes, if you don't need to dynamically load the libraries from the script, your solution is much cleaner and easier to maintain.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This topic is closed to new replies.

Advertisement