December 07, 2019, 12:47:30 PM

Author Topic: Use a BlitzMax NG dll in Haxe  (Read 97 times)

Offline rc

  • Jr. Member
  • **
  • Posts: 3
Use a BlitzMax NG dll in Haxe
« on: November 27, 2019, 09:19:08 PM »
Hello Community

I'm developing in BlitzMax for over 15 years now and I am really happy to see that BlitzMax still exists. I'm a software developer and I use c# and python at work, but for hobby projects I like to use BlitzMax.

However, I was wondering if it is possible to create a dll in BMax ng and use it in a Haxe application with cpp as build target.

I have created a dlltest.dll with BlitzMax ng (Creating DLLs)
with the following code:
Code: [Select]
Function TheAnswer:Int() Export
Return 42
EndFunction

Buildsettings are:
App Options: Build Shared Library
Platform: Win32
Architecture: x64

So the  calling convention cdecl.



In Haxe i have the following code:
lib.load

Code: [Select]
class Main {

static var InitBRL:()->Int =  cpp.Lib.load("dlltest","InitBRL",0);
static var TheAnswer:()->Int = cpp.Lib.load("dlltest","TheAnswer",0);

static function main():Void {
InitBRL();
trace(TheAnswer());
}
}

With the following build parameters:
Code: [Select]
-cp src
-cpp cpp
-D analyzer-optimize
-main Main

Haxe builds the exe without eny errors. However, when i execute the exe, i get the following errors:

Code: [Select]
Error : Could not load module dlltest@InitBRL__0
Error : Could not load module dlltest@TheAnswer__0

The .def file generated by BlitzMax NG is:
Code: [Select]
[code]LIBRARY dlltest
EXPORTS
TheAnswer
InitBRL

I also looked into the c output of BMax ng:
Code: [Select]
BBINT TheAnswer(){
return 42;
}
BBINT InitBRL(){
bbLibInit();
return 0;
}

So this looks fine.

Can someone give me some advice on how i get this working?

Offline Derron

  • Hero Member
  • *****
  • Posts: 2607
Re: Use a BlitzMax NG dll in Haxe
« Reply #1 on: November 29, 2019, 07:01:39 AM »
I created some DLL with NG (but all for the same project - so approach stuff similar).

Instead of exposing "initBRL" (so others need to know that they call this before everything else - to eg make the GC working). I have this function in my DLL:

Code: BlitzMax
  1. ' === DLL STARTUP FUNCTIONS ===
  2. Global dllInitDone:Int = False
  3. Function InitDLL:Int()
  4.         If dllInitDone Then Return True
  5.  
  6.         InitBRL()
  7.         dllInitDone = True
  8.         Return True
  9. End Function
  10.  

Then in each exposed function I do

Code: BlitzMax
  1. Function MyDLL_IsMeasurementDone:Int() Export
  2.         InitDLL()
  3.  
  4.         Return measurementDone
  5. End Function
  6.  

Yes, a bit tedious - but this is to hide the "initBRL()" thing. Nothing you need to do if it is your DLL and you yourself are using it :)



If something is run in threads somehow, make sure that the function is registered in that thread:
Code: BlitzMax
  1. Function _MyDLL_MeasurementDoneCallback(deviceID:Int, errorCode:Int, userContext:Byte Ptr)
  2.         If Not GCThreadIsRegistered() Then GCRegisterMyThread()
  3. [...]
  4. End Function
  5.  



Next is to build - as you did. And then maybe validate first, that the DLL works as expected by using it straight in BlitzMax (or C). Then later on you can try to make it work with Haxe.

test:
Code: BlitzMax
  1. Print "Loading DLLs"
  2. Global dllHandle:Byte Ptr = LoadLib("mydll.dll")
  3.  
  4. Global MyDLL_IsMeasurementDone:Int() = GetProcAddress(dllHandle, "MyDLL_IsMeasurementDone")
  5.  


For haxe - maybe you need to export not as _cdecl but stdcall (MVSC style)? In BlitzMax I think this is if you export with "Win32". Brucey told me multiple times to only do this if I knew what I do. -- what I don't ;D


bye
Ron

Offline Derron

  • Hero Member
  • *****
  • Posts: 2607
Re: Use a BlitzMax NG dll in Haxe
« Reply #2 on: November 29, 2019, 07:05:14 AM »
@ Win32

DLL:
Code: BlitzMax
  1. Global versionPtr:Byte Ptr = "My Super DLL v1.0".ToCString()
  2.  
  3. Function MyDLL_GetVersion:Byte Ptr() Export "Win32"
  4.         InitDLL()
  5.         Return versionPtr
  6. End Function
  7.  

Test:
Code: BlitzMax
  1. Global MyDLL_GetVersion$z() "Win32" = GetProcAddress(dllHandle, "MyDLL_GetVersion")
  2.  
  3.  
  4. Print "dll version: " + MyDLL_GetVersion()
  5.  


bye
Ron

Offline rc

  • Jr. Member
  • **
  • Posts: 3
Re: Use a BlitzMax NG dll in Haxe
« Reply #3 on: November 29, 2019, 10:32:04 AM »
Hello Ron

Thanks for the detailed answer.

I'm wondering where LoadLib is comming from?
Is this a build-in function from bmax-ng?

Just trying to verify the dll by loading it in bmax as you have suggested.
However i get the error:
Code: [Select]
Identifier loadlib not defined
When i try this, it works with bmax:
Code: [Select]
Global dllHandle:Byte Ptr = LoadLibraryA("dlltest.dll")

Global Test:Int() = GetProcAddress(dllHandle,"Test")

Print(Test())

Dll code:
Code: [Select]
' === DLL STARTUP FUNCTIONS ===
Global dllInitDone:Int = False
Function InitDLL:Int()
        If dllInitDone Then Return True
 
        InitBRL()
        dllInitDone = True
        Return True
End Function

Function Test:Int() Export
InitDLL()
Return 66
End Function

However, loading it in Haxe still results in the same error.
Code: [Select]
Error : Could not load module dlltest@Test__0
Code: [Select]
import cpp.Lib;

class Main
{
    static var Test:()->Int = Lib.load("dlltest", "Test", 0);

    static function main()
    {
        trace(Test());
    }
}

Offline Derron

  • Hero Member
  • *****
  • Posts: 2607
Re: Use a BlitzMax NG dll in Haxe
« Reply #4 on: November 29, 2019, 11:29:23 AM »
loadlib - convenience function by me (to check file existence etc).

what happens if you do

Function Test:Int() "Win32" Export

adding that "Win32" will make it use another convention when exporting.


Edit: googled for "Haxe load dll" and this was one of the first hits:
http://old.haxe.org/forum/thread/756
https://stackoverflow.com/questions/42599263/how-to-use-third-part-dll-from-haxe

bye
Ron

Offline rc

  • Jr. Member
  • **
  • Posts: 3
Re: Use a BlitzMax NG dll in Haxe
« Reply #5 on: November 29, 2019, 12:26:26 PM »
Yes I also googled. I found the second one but not the first one. Not being able to load a third  party dll directly in Haxe is really a bummer.
My intention was to wrap some basic Max2D functions like initializing the graphics context, loading and drawing images and so on, so I could use it within haxe. But that does not seem to work then.