Compiling a .dll from bmx code?

BlitzMax Forums/BlitzMax Programming/Compiling a .dll from bmx code?

plash(Posted 2007) [#1]
Exactly as the title describes.


Dreamora(Posted 2007) [#2]
You can't

BM has inofficially the support for generating DLLs but you will need to do some stuff by hand (manually calling bmk from command line and manually create the DEF file upfront with the exported function declaration)


kfprimm(Posted 2007) [#3]
Thats contradicting Dreamora.....


Fabian.(Posted 2007) [#4]
You can

here's an example:
1. create any folder where you'll create your dll in.
the file names I'll tell you refer to this folder.
2. create a file "DLLTest.bmx"
3. this should be the file content:
Strict
Framework brl.blitz

Function Product ( A , B )
  Return A * B
EndFunction
4. create a file "DLLTest.def"
5. here's the file's content:
EXPORTS
Product=bb_Product
6. open a command prompt
7. if you haven't added the "bin" directory of your BlitzMax installation to the "Path" environment variable, you need to change the current directory to this directory using the CD command.
8. call
bmk.exe makelib bmx-file-path
for debug or
bmk.exe makelib -r bmx-file-path
for release version
("bmx-file-path" needs to be a path to the "DLLTest.bmx" file)
9. the dll is now created, it's named "DLLTest.dll" - to test whether the dll is working do the following:
10. create a file "DLLCaller.bmx"
11. the file's contents are:
Strict
Framework brl.blitz

Import pub.win32

Local Library = LoadLibraryA ( "DLLTest.dll" )
If Not Library
  WriteStdout "Library not found!~n"
  Return
EndIf
Local Product ( A , B ) = GetProcAddress ( Library , "Product" )
If Not Product
  WriteStdout "Product function not found!~n"
  Return
EndIf
WriteStdout "The product of 3 and 5 is " + Product ( 3 , 5 ) + ".~n"
FreeLibrary Library

Extern "Win32"
  Function FreeLibrary ( Library )
EndExtern
12. build and run the file, if the output is
The product of 3 and 5 is 15.
you've successfully built and tested a dll using BlitzMax


plash(Posted 2007) [#5]
I got an error on the command prompt part.

T:\Program Files\BlitzMax\bin>bmk.exe makelib -r ..\test1\DLLTest.bmx
Compiling:DLLTest.bmx
flat assembler version 1.66
3 passes, 329 bytes.
Linking:DLLTest.dll
T:/Program Files/BlitzMax/bin/ld.exe: cannot find T:/Program Files/BlitzMax/lib/dllcrt2.o
Build Error: Failed to link T:/Program Files/BlitzMax/test1/DLLTest.dll
Press any key to continue . . .


What is dllcrt2.o?


EDIT: I looked in my lib folder and found a file named "crt2.o", is it possible this just needs to be renamed or do I need to rebuild my modules?


kfprimm(Posted 2007) [#6]
move dllcrt2.o from your MinGW\lib directory into your BlitzMax\lib directory.


plash(Posted 2007) [#7]
T:\Program Files\BlitzMax\bin>bmk.exe makelib DLLTest.bmx
Linking:DLLTest.dll
T:/Program Files/BlitzMax/bin/ld.exe: cannot open T:/Program: No such file or directory
Build Error: Failed to link T:/Program Files/BlitzMax/bin/DLLTest.dll
Press any key to continue . . .


..don't tell me I have to reinstall bmax to a location with no spaces :(


grable(Posted 2007) [#8]
i tried it myself, and it seems just the project itself must be on a path with no spaces.


plash(Posted 2007) [#9]
Okay, that worked..


plash(Posted 2007) [#10]
So how would I return data to the parent program from the dll without ending the execution of the function (without using the command "Return")??


JoshK(Posted 2007) [#11]
The only part of BlitzMax I have had problems with in a dll is MaxGUI. It would be nice if this worked, because sometimes you have an options interface for import/export plugins.


grable(Posted 2007) [#12]
Just use another function for that, or a var parameter, or a pointer.


plash(Posted 2007) [#13]
So like...
in the dll "Global Var$ = "hello"

and in the caller "var = GetProcAddress ( Library , "var" )"

then in the def "var=bb_var"??


grable(Posted 2007) [#14]
You can only export Functions from a dll,

so more like this:
'DLL
Function GetData( output:Int Var)
  output = 10
EndFunction

'APP
Global data:Int
GetData( data)


or this:
'DLL
Function InitDll:Int()
  Return your_data
EndFunction

Function DoSomethingElse()
EndFunction

'APP
Global data:Int = InitDll()
DoSomeThingElse()



plash(Posted 2007) [#15]
I'm having trouble trying to get that to work..

DLLTest2.bmx
Strict
Framework brl.blitz

Function GetData( output:Int Var)
  output = 10
EndFunction


DllCaller2.bmx
Strict
Framework brl.blitz

Import pub.win32


Global data:Int = 0

Local Library = LoadLibraryA ( "DLLTest2.dll" )
If Not Library
  WriteStdout "Library not found!~n"
  Return
EndIf
Local GetData ( A ) = GetProcAddress ( Library , "GetData" )
If Not Getdata
  WriteStdout "GetData function not found!~n"
  Return
EndIf
GetData( data )
WriteStdout data
FreeLibrary Library

Extern "Win32"
  Function FreeLibrary ( Library )
EndExtern


DLLTest2.def
EXPORTS
GetData=bb_GetData



I get "Unhandled Memory Exception Error" when trying to call "GetData( data )".


grable(Posted 2007) [#16]
You need to declare the function pointer with var as well.
Local GetData ( A:Int Var ) = GetProcAddress ( Library , "GetData" )

That should do it =)


plash(Posted 2007) [#17]
Okay, it worked, thanks.

And one more question, when I call a function from a dll, does it pause the execution of the parent program? EDIT: Ofcourse it does!


Brendane(Posted 2007) [#18]
The dll code you call is executed in the same thread.. so, it's just like calling one of your own program's functions (ie, when the dll function returns, your code continues at the next instruction)


plash(Posted 2007) [#19]
Figured that, thanks.


Fabian.(Posted 2007) [#20]
You can only export Functions from a dll
Not quite, globals can also be exported, it's just important that the caller now needs to refer to the symbol as pointer.
Here's an example:
DLLTest.bmx:
Strict
Framework brl.blitz

Global Variable
DLLTest.def:
EXPORTS
Variable=bb_Variable
DLLCaller.bmx:
Strict
Framework brl.blitz

Import pub.win32

Local Library = LoadLibraryA ( "DLLTest.dll" )
If Not Library
  WriteStdout "Library not found!~n"
  Return
EndIf
Local Variable Ptr = Int Ptr GetProcAddress ( Library , "Variable" )
If Not Variable
  WriteStdout "Variable not found!~n"
  Return
EndIf
Variable [ 0 ] = 53
WriteStdout "Variable is " + Variable [ 0 ] + ".~n"
FreeLibrary Library

Extern "Win32"
  Function FreeLibrary ( Library )
EndExtern
The calling instance always needs to use the [0] when accessing the variable. If I remember correctly, it was in version 1.12 or 1.14 where you could write:
Local Variable Var = Var Int Ptr GetProcAddress ( Library , "Variable" )
and then you could access the variable as normal, so "Variable = value" to write and "Variable" to read values, without any need for [0] - but this feature disapeared since version 1.18 I think.

The only thing that can't be exported from dlls are types and objects, the problem is that the type would either exist twice, once in the dll and once in the main programm, or the caller couldn't access the object's fields and methods because it has no declaration of the types.

P.S.: I'm sorry, I've forgotten to tell you about copying the dllcrt2.o file, but Khomy Prime explained it perfectly.


plash(Posted 2007) [#21]
Yeah, thanks for that example though, it did just what I needed.


JoshK(Posted 2007) [#22]
I think you need to add "win32" to the end of every function in both the dll and main program source.

I also think you need to have GCEnter() as the first line of every dll function.