DLL creation

BlitzMax Forums/BlitzMax Programming/DLL creation

Ive had a search and there seems to be a few differences of opinion. Is it possible (and stable) to create a dll/s in blitzmax and if so... are there any small guides/samples?

hmm interesting question. Could we create a .DLL that could be used in other programs? In other languages?

Theres countless examples in the forums, and as far as i know its pretty stable.
And since they are normal DLLs any application can use them.
But for completeness il put it all here in one place.

First heres some helper tools to help automate the process.

makedef.bmx - creates def files from blitzmax sources (see the 'EXPORT appended to functions in the dll source)
Framework BRL.Blitz
Import BRL.StandardIO
Import BRL.Stream
Import BRL.FileSystem

SuperStrict

If AppArgs.Length <= 1 Then
	Local fn:String = StripExt(StripDir(AppArgs[0]))
	Print fn + ": makes exports def file from blitzmax source"
	Print "syntax:"
	Print "~t" + fn + " filename.bmx"
	Print "~t- creates filename.def of functions marked with 'EXPORT"
	End
EndIf

' create output def file
Local defn:String = StripExt(AppArgs[1]) + ".def"
Global def:TStream = WriteStream( defn)
If Not def Then 
	WriteStderr "** error writing to def file: " + defn + "~n"
	exit_(1)
EndIf
def.WriteLine( "EXPORTS")

' keep track of rem/endrem
Global remblock:Int

' read the input source
If Not ParseSource( AppArgs[1]) Then
	WriteStderr "~n** there were errors parsing the source files~n"	
	def.Close()
	exit_(1)
EndIf

def.Close()
End


Function ParseSource:Int( fn:String)
	Local stream:TStream = ReadStream( fn)
	If Not stream Then
		WriteStderr "** error reading input file: " + fn + "~n"
		Return False
	EndIf

	' read each line from input
	While Not stream.Eof()
		Local i:Int, s:String = stream.ReadLine().Trim()
		If StartsWith( s, "Rem") Then
			If (s.Length > 3) Then
				If ((s[3] = Asc("'")) Or (s[3] = Asc(" ")) Or (s[3] = Asc("~t"))) Then 
					remblock :+ 1
				EndIf
			Else
				remblock :+ 1
			EndIf
		ElseIf StartsWith( s, "EndRem") Then
			If (s.Length > 6) Then
				If ((s[6] = Asc("'")) Or (s[6] = Asc(" ")) Or (s[6] = Asc("~t"))) Then 
					remblock :- 1
				EndIf
			Else
				remblock :- 1
			EndIf
		ElseIf (StartsWith( s, "Function ") Or StartsWith( s, "Function~t")) And EndsWith( s, "'EXPORT") Then
			If remblock = 0 Then
				s = s[9..]
				i = s.Find("(")
				If i <> -1 Then
					s = s[..i]
					i = s.Find( ":") 
					If i <> -1 Then s = s[..i]
					def.WriteLine( "~t" + s + "=bb_" + s)
				EndIf
			EndIf
		ElseIf StartsWith( s, "Include ") Then
			If remblock = 0 Then
				s = s[9..s.Length-1]
				If Not ParseSource( s) Then 
					stream.Close()
					Return False
				EndIf
			EndIf
		EndIf
	Wend
	stream.Close()
	Return True
EndFunction

' case insensitive versions
Function StartsWith:Int( s:String, val:String)	
	Return s[..val.Length].ToLower() = val.ToLower()
EndFunction

Function EndsWith:Int( s:String, val:String)
	Return s[s.Length - val.Length..].ToLower() = val.ToLower()
EndFunction


makelib.cmd - for easy creation of def file & compiling dll (allows spaces in the path as well as drag & drop!
@echo off
if not %1 == "" (
	cd %~dp1
	makedef %~nx1
	pushd .
	command /c bmk makelib -r %~n1
	popd
)

You also need to copy dllcrt2.o from your mingw\lib dir to your blitzmax\lib dir. (thanks jsp!)
And add blitzmax\bin to your PATH environment variable.


And heres the actual application + dll sources

app.bmx
Framework BRL.Blitz

Import BRL.StandardIO
Import PUB.win32

SuperStrict

' load the dll
Local lib:Int = LoadLibraryA( "dlltest.dll")
If Not lib Then RuntimeError "Library not found!"

' get its function
Global ShowMessage() "Win32" = GetProcAddress( lib, "ShowMessage")
If Not ShowMessage Then RuntimeError "ShowMessage() not found!"

' test the dll function
ShowMessage()

' free the dll
FreeLibrary( lib)


Extern "Win32"
  Function FreeLibrary:Int( lib:Int)
EndExtern


dlltest.bmx
Framework BRL.Blitz

SuperStrict

Const COMPILE_DLL:Int = True

Function ShowMessage() "Win32" 'EXPORT
	If COMPILE_DLL Then GCEnter()
	MessageBoxA 0, "Hello world from DLL!", "MessageBox", 0
EndFunction

Extern "Win32"
	Function MessageBoxA:Int( hwnd:Int, message$z, title$z, buttons:Int)
EndExtern


Compiling the dll & application:
makelib dlltest.bmx
bmk makeapp -r app.bmx


EDIT: makedef.bmx didnt handle Rem/EndRem properly & added Include handling.
EDIT2: fixed batch file to handle drag & drop

Don't forget to copy dllcrt2.o from your MinGW\lib directory into your BlitzMax\lib directory.

And to have drag and drop working from any location you may like to add a cd command (blitzmax bin directory) to the makelib.cmd file.

Oops, forgot about that one.. =)

Its also good idea to add your blitzmax bin dir to your path, as you should with mingw.

whoah.... I may have to play with this when I have time, but it sounds like I could make my little 2d engine be useable from any other language. hmm.... BIG hmm....

whoah.... I may have to play with this when I have time, but it sounds like I could make my little 2d engine be useable from any other language. hmm.... BIG hmm....


You're going to have a lot of issues with garbage collection if you try.