DLL creation, second attempt

BlitzMax Forums/BlitzMax Programming/DLL creation, second attempt

I couldn't resist Halo's DLL-creation challenge so I gave it another go.

This time I think I came up with a pretty good solution.
It doesn't require MingW and therefore it doesn't need to be a module.

You will find the download below...
Check the readme and the demo.bmx file inside the ziparchive for further instructions...
http://www.svenberra.net/MakeDLL.zip

Yes, the commandlinetool looks exactly like the one skn3[ac] made. Hope you don't mind skn3[ac] :)

Hopefully someone could improve the tool and make the process even simpler.

This version works with spaces in filepaths/names:
Strict

' ***********************************
' * MakeDLL                         *
' * By Sven-Bertil Blom AKA Sweenie *
' * 2005-08-12                      *
' ***********************************
'
' Commandlinearguments-code borrowed from skn3[ac]
'
Local file:TStream
Local bmaxpath:String
Local source:String

If appargs.length > 2
	file = WriteFile("bmaxpath.txt")
	If Not(Right(AppArgs[2],1)="") Then AppArgs[2] :+ ""
	file.WriteLine(AppArgs[2])
	file.close()
	bmaxpath = AppArgs[2]
	source = AppArgs[1]
ElseIf appargs.length > 1
	If FileType("bmaxpath.txt") <> 1
		Print "You didn't supply a blitzmax path. MakeDll will save the path when you supply it, and reuse it next time if left out of the commandline"
		End
	End If
	file = ReadFile("bmaxpath.txt")
	bmaxpath = file.ReadLine()
	file.Close()
	source = AppArgs[1]
Else
	Print "*** MakeDLL ***"
	Print "How To Use:"
	Print ""
	Print "  MakeDll.exe sourcepath bmaxpath"
	Print ""
	Print "[bmaxpath]"
	Print "This param is optional, you must use it the first time you call makedll, or anytime you want to modify the bmaxpath. The path will be saved and reused when no bmaxpath is specified"
	End
End If

'check correct bmax path
If FileType(bmaxpath+"bin\bmk.exe") <> 1
	Print "Invalid bmax root path"
	End
End If
	
'check correct source path
source = RealPath(source)
If FileType(source) <> 1
	Print "Can't find bmax source file"
	End
End If

Local sourcepath:String = ExtractDir(source)
If Not(Right(sourcepath,1)="/") Then sourcepath :+ ""
Local sourcename:String = StripExt(StripDir(source))

If FileType(sourcepath+sourcename+".exe") = 1
	DeleteFile(sourcepath+sourcename+".exe")
End If
If FileType(sourcepath+sourcename+".dll") = 1
	DeleteFile(sourcepath+sourcename+".dll")
End If

system_(bmaxpath+"bin\bmk.exe makeapp -r -t console ~q"+source+"~q")

'Parse sourcefile for exported functions...
Print "Parsing sourcefile..."
Local sfile:TStream = ReadFile(source)
Local dfile:TStream = WriteFile(sourcepath+"makedll.def")
WriteLine(dfile,"EXPORTS")
Local tmpline:String
Local indx:Int
Local expfunc:String
tmpline = sfile.ReadLine()
Print "Exported functions:"
While Not sfile.Eof()
	If tmpline.Find("'EXPORT")>-1 And tmpline.Find("Function")>-1 Then
		expfunc=""
		indx = tmpline.Find("Function")+10
		'Print tmpline
		While Mid(tmpline,indx,1)<>"(" And Mid(tmpline,indx,1)<>":"
		 expfunc :+ Mid(tmpline,indx,1)
		 indx :+ 1
		Wend	
		Print " "+expfunc
		WriteLine(dfile,Chr(9)+expfunc + " = bb_" + expfunc)
	EndIf
	tmpline = sfile.ReadLine()
Wend
dfile.Close()
sfile.Close()
system_(bmaxpath+"bin\ld.exe --dll -o ~q"+sourcepath+sourcename+".dll~q -L ~q"+bmaxpath+"lib~q -e _bb_DllMain ~q"+sourcepath+"makedll.def~q ~q"+bmaxpath+"tmp\ld.tmp~q")
If FileType(sourcepath+sourcename+".dll") <> 1
 Print "Creation of "+sourcename+".dll failed"
Else
 Print "Creation of "+sourcename+".dll successful"
End If

If FileType(sourcepath+sourcename+".exe") = 1
	DeleteFile(sourcepath+sourcename+".exe")
End If
If FileType(sourcepath+"makedll.def") = 1
	DeleteFile(sourcepath+"makedll.def")
End If
Oh, and top job it seems to work perfectly!

Thanks for the addition!

Beers are on me!

Any ideas why message requesters in the dll's produces a memory access violation, when it's called?

I'm currently investigating that.
I'm not quite sure how Bmax messageboxes works, but maybe it's expecting something to be initialized before using them and when running the blitzapp as a dll, that init-function never runs. Just speculating though.
It's the same for the Print function.

When browsing through the symbols inside some blitzapps I noticed an entry called bb_main, which is probably the entrypoint for the exe's.
The entry point for the dll's is the DllMain function.

I let you know if I find something.

As I suspected the Notify function is a member of an instance called Driver(TSystemDriver)
My best guess is that the Driver-object never get's initialized when the app is run as a dll.

But since Notify is a wrapped method for the User32 MessageBoxA function you could use that API function directly instead.
Like this...


Framework BRL.Blitz

Extern "win32"
 Function MessageBoxA:Int(hWnd:Byte Ptr,lpText$z,lpCaption$z,uType:Int)
End Extern

Function DllMain(hinstDLL:Byte Ptr,fdwReason:Int,lpvReserved:Byte Ptr)"win32"
 Return True
End Function

Function AddIntegers:Int(a:Int,b:Int)"win32"	'EXPORT   
 MessageBoxA(Null,"The result of "+a+" + "+b+" = "+(a+b),"Result:",0)
End Function



[Edit]
And the Common Dialogue api(comdlg32, not linked by default) if you want fileopen/save requesters, printerselector and so on.

nice one :) gonna throw myn in de recycle bin now ;)

Sweenie,
I try but has this error..

Parsing sourcefile...
Exported functions:
AddIntegers
GetText
Creation of demo.dll failed

is there any way to capture the output of the system_ call?

@Mag, Do you have spaces somewhere in the path?, if so, try fredborg's version.

@Chris C.
Not sure, but maybe there is some apifunction that let you set the stdout.
Try searching codeproject.com, they usually have examples and tutorials for such things.