1. Wrapping Callback Functions
- Posted by Icy_Viking Oct 31, 2020
- 987 views
Hello all,
I need a little help. I'm wondering if this is how you wrap callback functions.
//C Code typedef void* (*NewtonAllocMemory) (int sizeInBytes); typedef void (*NewtonFreeMemory) (void* const ptr, int sizeInBytes);
--Is this correct? constant xNewtonAllocMemory = define_c_func(dll,"NewtonAllocMemry",{C_INT},C_POINTER) public function NewtonAllocMemory(integer size) return c_func(xNewtonAllocMemory,{size}) end function constant xNewtonFreeMemory = define_c_proc(dll,"NewtomFreeMemory",{C_POINTER,C_INT}) public procedure NewtonFreeMemory(atom ptr,integer size) c_proc(xNewtonFreeMemory,{ptr,size}) end procedure
2. Re: Wrapping Callback Functions
- Posted by petelomax Oct 31, 2020
- 979 views
--Is this correct? constant xNewtonAllocMemory = define_c_func(dll,"NewtonAllocMemry",{C_INT},C_POINTER) -- It looks ok, ^ apart from that constant xNewtonFreeMemory = define_c_proc(dll,"NewtomFreeMemory",{C_POINTER,C_INT}) -- ^ and that
3. Re: Wrapping Callback Functions
- Posted by Icy_Viking Oct 31, 2020
- 958 views
--Is this correct? constant xNewtonAllocMemory = define_c_func(dll,"NewtonAllocMemry",{C_INT},C_POINTER) -- It looks ok, ^ apart from that constant xNewtonFreeMemory = define_c_proc(dll,"NewtomFreeMemory",{C_POINTER,C_INT}) -- ^ and that
Is the name in quotes not supposed to be there? Or do I need to add a + in front of the name?
4. Re: Wrapping Callback Functions
- Posted by irv Oct 31, 2020
- 953 views
Spelling counts, but beside that -
As far as I know, putting a + in front of the name is a good idea, at least on Windows.
5. Re: Wrapping Callback Functions
- Posted by petelomax Oct 31, 2020
- 991 views
Is the name in quotes not supposed to be there?
YOU CANNOT BE SERIOUS!!! The names in quotes are supposed to be spelt correctly....
(And yes/as irv said, a + may well help)
6. Re: Wrapping Callback Functions
- Posted by Icy_Viking Oct 31, 2020
- 954 views
Is the name in quotes not supposed to be there?
YOU CANNOT BE SERIOUS!!! The names in quotes are supposed to be spelt correctly....
(And yes/as irv said, a + may well help)
Oops, just noticed the typo. My eyesight isn't what it used to be. I thought something was wrong with the entire quotes.
7. Re: Wrapping Callback Functions
- Posted by irv Oct 31, 2020
- 942 views
You can save some grief if you assign a type for the callbacks, so that you get notified when you try to look up an invalid c routine, otherwise, you have to check each one to see if it succeeds. Something like this, off the top of my head:
type handle(integer x) return x > -1 end type handle xNewtonAllocMemory = define_c_func(dll,"+NewtonAllocMemory",{C_INT},C_POINTER) handle xNewtonFreeMemory = define_c_proc(dll,"+NewtonFreeMemory",{C_POINTER,C_INT})
8. Re: Wrapping Callback Functions
- Posted by ghaberek (admin) Nov 02, 2020
- 958 views
Hello all,
I need a little help. I'm wondering if this is how you wrap callback functions.
//C Code typedef void* (*NewtonAllocMemory) (int sizeInBytes); typedef void (*NewtonFreeMemory) (void* const ptr, int sizeInBytes);
No, that is not at all correct. These are typedefs which name a new type. In this case, that type is the signature of each call back function. They're call backs which means they're addresses of functions where the library calls you. (Insert Yakov Smirnoff joke here.)
Call back functions by their nature should not exist in the library you're calling. The docs for NewtonAlocMemory even state: This is not a library function, but a callback event. So you need to define your call back functions to match the signatures as provided. In Euphoria, that means each parameter must be an atom.
Then the library should have a way to set those call back addresses so it can call your function when the time comes. In this case it looks like that's NewtonSetMemorySystem. Which, by the way, states it is not neccesary to call this function at all in the documentation, so in this particular case all of this work may be moot (unless you want to set up custom memory allocation).
Edit: since we've determined this uses cdecl on 32-bit Windows, we also need to preface our call backs with '+' to force cdecl inside Euphoria.
-- -- This is the library function to set the call backs. -- constant xNewtonSetMemorySystem = define_c_proc( newton "NewtonSetMemorySystem", {C_POINTER,C_POINTER} ) -- void NewtonSetMemorySystem (NewtonAllocMemory malloc, NewtonFreeMemory free) public procedure NewtonSetMemorySystem( atom malloc_func, atom free_func ) c_proc( xNewtonSetMemorySystem, {malloc_func,free_func} ) end procedure -- -- This is our implementation of the alloc function. -- -- typedef void* (*NewtonAllocMemory) (int sizeInBytes); function NewtonAllocMemory( atom sizeInBytes ) return allocate( sizeInBytes ) end function constant NewtonAllocMemory_id = routine_id( "NewtonAllocMemory" ) constant NewtonAllocMemory_cb = call_back({ '+', NewtonAllocMemory_id }) -- -- This is our implementation of the free function. -- -- typedef void (*NewtonFreeMemory) (void* const ptr, int sizeInBytes) function NewtonFreeMemory( atom ptr, atom sizeInBytes ) free( ptr ) return NULL end function constant NewtonFreeMemory_id = routine_id( "NewtonFreeMemory" ) constant NewtonFreeMemory_cb = call_back({ '+', NewtonFreeMemory_id }) -- -- Call the library function to set the call back addresses. -- NewtonSetMemorySystem( NewtonAllocMemory_cb, NewtonFreeMemory_cb )
-Greg
9. Re: Wrapping Callback Functions
- Posted by ghaberek (admin) Nov 02, 2020
- 897 views
One neat feature that was implemented in Euphoria 4.0 (or maybe 4.1? can't remember) but not really advertised is the "stacking" of default parameters that are evaluated at runtime at the callee's location.
What I mean by "stacking" is that parameters are evaluated from left to right, so you can use a previous parameter's value later down the line. So you can "clean up" code above by adding a few default parameters:
Edit: since we've determined this uses cdecl on 32-bit Windows, we also need to preface our call backs with '+' to force cdecl inside Euphoria.
public procedure NewtonSetMemorySystem( sequence malloc_name, sequence free_name, integer malloc_id=routine_id(malloc_name), integer free_id=routine_id(free_name) ) atom malloc_cb = call_back({ '+', malloc_id }) atom free_cb = call_back({ '+', free_id }) c_proc( xNewtonSetMemorySystem, {malloc_cb,free_cb} ) end procedure
And now you can eliminate all the separate calls to routine_id and call_back and just call NewtonSetMemorySystem like this:
function NewtonAllocMemory( atom sizeInBytes ) return allocate( sizeInBytes ) end function function NewtonFreeMemory( atom ptr, atom sizeInBytes ) free( ptr ) return NULL end function NewtonSetMemorySystem( "NewtonAllocMemory", "NewtonFreeMemory" )
-Greg
10. Re: Wrapping Callback Functions
- Posted by ghaberek (admin) Nov 02, 2020
- 928 views
Is the name in quotes not supposed to be there?
YOU CANNOT BE SERIOUS!!! The names in quotes are supposed to be spelt correctly....
(And yes/as irv said, a + may well help)
Oops, just noticed the typo. My eyesight isn't what it used to be. I thought something was wrong with the entire quotes.
So this raises the following questions:
What is the '+' for?
The '+' character is used to force the cdecl calling convention on 32-bit Windows, where the default is stdcall (which is strictly an x86 convention). On any other system, and all 64-bit systems, the default is already cdecl, so the '+' has no effect.
Therefore, if you're using a library that requires cdecl on 32-bit Windows, you can wrap it with '+' in the function names without having to maintain two separate versions with and without '+' everywhere.
How do we know when to use '+'?
This can be a little tricky. You need to dig into the code a little. If you walk through the header you should see if it defines any particular calling convention.
If we start at the definition for a function, like NewtonSetMemorySystem we see it's defined as:
NEWTON_API void NewtonSetMemorySystem (NewtonAllocMemory malloc, NewtonFreeMemory free);
That NEWTON_API macro is likely going to contain our calling convention, if the authors of the library have intended to change it.
Sure enough, if we scroll up to the top of Newton.h we find several ifdef's that control the content of the NEWTON_API macro.
#if defined(_MSC_VER) #define DG_LIBRARY_EXPORT __declspec(dllexport) #define DG_LIBRARY_IMPORT __declspec(dllimport) #define DG_LIBRARY_STATIC #else #define DG_LIBRARY_EXPORT __attribute__((visibility("default"))) #define DG_LIBRARY_IMPORT __attribute__((visibility("default"))) #define DG_LIBRARY_STATIC #endif #ifdef _NEWTON_STATIC_LIB #define NEWTON_API DG_LIBRARY_STATIC #elif defined(_NEWTON_BUILD_DLL) #define NEWTON_API DG_LIBRARY_EXPORT #else #define NEWTON_API DG_LIBRARY_IMPORT #endif
Which means if the library is built as shared library (dll/so) and on Visual Studio (where _MSC_VER is defined) then the value of NEWTON_API will become __declspec(dllexport), which is the cdecl calling convention.
-Greg
11. Re: Wrapping Callback Functions
- Posted by Icy_Viking Nov 02, 2020
- 884 views
Thanks for all your help Greg. The new function routines and helpers in 4.1 really help with wrapping libraries. We really are just missing a struct function in Euphoria. Which would also greatly help with wrapping certain libraries.
12. Re: Wrapping Callback Functions
- Posted by ghaberek (admin) Nov 02, 2020
- 890 views
Thanks for all your help Greg. The new function routines and helpers in 4.1 really help with wrapping libraries.
You're welcome, glad to be of help.
We really are just missing a struct function in Euphoria. Which would also greatly help with wrapping certain libraries.
I've been digging into the Euphoria source to better understand how to finish Matt's work on memstruct as described here: https://openeuphoria.org/forum/134782.wc
So far it's been slow-going but it's coming together. Just takes a while to understand how all the little parts and pieces work with each other to do what they do.
-Greg
13. Re: Wrapping Callback Functions
- Posted by Icy_Viking Nov 02, 2020
- 893 views
Thanks for all your help Greg. The new function routines and helpers in 4.1 really help with wrapping libraries.
You're welcome, glad to be of help.
We really are just missing a struct function in Euphoria. Which would also greatly help with wrapping certain libraries.
I've been digging into the Euphoria source to better understand how to finish Matt's work on memstruct as described here: https://openeuphoria.org/forum/134782.wc
So far it's been slow-going but it's coming together. Just takes a while to understand how all the little parts and pieces work with each other to do what they do.
-Greg
That's good to hear Greg.