How do I call a delphi dll from blitzmax?

BlitzMax Forums/BlitzMax Programming/How do I call a delphi dll from blitzmax?

netmaestro(Posted 2005) [#1]
Most of the dll's I have written have been done in Delphi. Could someone please tell me the best (right?) way to call them in a blitzmax program?


WPOSTMA(Posted 2012) [#2]
If someone could please find this out, i REALY need to know this. Thanks in advance. :P


col(Posted 2012) [#3]
Assuming you want to call the regular functions inside the dll, then I believe its the same as all other dlls.

The easiest way:-




Kryzon(Posted 2012) [#4]
Some DLLs have your functions with weird suffixes added [for whatever technical reason I'm not educated upon - probably indexing].
Things like "myDLLFunction1@7".

You can't guess how the DLL functions will be named (unless Delphi logs them for you while compiling), so you can use an utility like Dependency Walker to scan your DLL and tell you the real, suffixed names for all functions inside it:

http://www.dependencywalker.com/

These final names with suffixes are what should be input to GetProcAddress() like Col showed above.

Last edited 2012


WPOSTMA(Posted 2012) [#5]
Would this work with procedures in a dll made in delphi or only with functions?


Kryzon(Posted 2012) [#6]
I think procedures and functions should work the same. What matters is if you mark them for exporting.

See these articles:
http://delphi.about.com/od/windowsshellapi/a/dll_basics.htm
http://www.esanu.name/delphi/DLL/Calling%20delphi%20DLL%20from%20MS%20Visual%20C.html

Last edited 2012


WPOSTMA(Posted 2012) [#7]
Using dependancy walker i found that the name of my function and my procedure where the exact same as i made them. But, i substituted them into the code col provided and they did not work. i got the error "EXCEPTION_ACCESS_VIOLATION" here is my code:
Global myDLL:Int = LoadLibraryA("hellodll.dll")    'Give a handle to the dll
Global myDLLFunction1(message:String)"Win32" = GetProcAddress(myDLL,"one")
Global myDLLFunction2()"Win32" = GetProcAddress(myDLL,"two")

'You need to make sure the parameters and parameters types all match obviously. You then call it as a regular function

myDLLFunction1("hello bobiemanmoboberfred")
CallMyDLL()

Function CallMyDLL()
    Local Result = myDLLFunction2()
    Return Result
EndFunction

one is my function and two is my procedure and for this i am currently using a test dll i made to get this working with. (both the function and the procedure send a message to the screen but the procedure one takes no parameters.

Last edited 2012


Yasha(Posted 2012) [#8]
Just to expand what Kryzon touched on in post #4:

The thing you probably need to read up on is "calling convention". All the DLL exposes is a list of raw pointers and their names, and the program needs to know how to actually use those for something (calling a function means loading arguments, unloading return value etc.). The "calling convention" is the way in which the assembly code will go about this, usually the distinction being whether the code before or after the jump does the hard work (you don't really need to know this stuff).

Ideally, you would know the calling convention. If not, you can take a guess: if the names you got from the DLL using Dependency Walker or whatever (I use FileAlyzer, myself) look like "_funcName@4", chances are that it's using the __stdcall convention, which I believe you communicate to BlitzMax by putting "Win32" after the names as above. If this is wrong, try putting "C" after the names where you currently have "Win32" to use a different one. Using the wrong calling convention will definitely cause an access violation (although it's obviously not the only possible cause).

Better yet, search the forums for "calling convention" and see what you get, because this is just a guess (I don't really know how to do this stuff); and search the internet to find out what the Delphi compiler may have used.


col(Posted 2012) [#9]
Hiya,

There are a couple of important gotchas to look out for.

Yasha and Kryzon are right about the call convention. You need to make sure the calling convention is the same in your BMax code and the Delphi code.

Add 'stdcall;' to the end of your Delphi function and use "Win32" on the end of your BMax function ( as above ) should fix this. ( EDIT2:- As a .dll is a windows file its best to use the 'standard' that MS suggest. Using the 'stdcall' or '__stdcall' for your exported functions will also allow your .dll to be use with any other coding language thats running on windows. ) If the calling convention doesnt match, and if youre lucky it it doesnt crash, then youll get unpredictable values. Its all to do passing parameters on and off the stack and who ( callee code or called code ) does the cleaning up. Very important that the calling conventions match.

The @x appended to the end of the function name is the size of bytes needed to pass the parameters. You don't have to use this, but it should still work if you do.
The name of the function in the GetProcAddress(dll,"This Name") is case sensitive, so needs to match exactly, otherwise you will get a Function not found error.

Dont use :String as used above in post#7, use either message:Byte Ptr, or message$w. String is a BMax object, so unless your dll function knows how to interpret BMax objects it will crash.

You can interact with BMax Types using :Byte Ptr, but we'll save that for another post as it can get confusing without a proper in-depth explanation.

The reason I suggested its easier is you can test if the dll variable or function pointers are valid. For eg...

myDLL = LoadLibraryA([...])
If Not myDLL Then 'ShowError'

If Not DLLFunctionOne Then 'ShowError'

Make sure youre in Debug mode to help catch any EAVs as the debugger may still give you the line it EAVd at, not always, but usually. And double check all of the above.

EDIT:_
As far as you sending a message to the screen, what do you mean? to the console window? what code creates the 'screen' or 'screen window'? do both/either BMax and Delphi know or need to know about the 'screen window'?
in Debug mode, the console window should be available to write to in both BMax and any other language your coding in. Im using c++ a lot lately ( only because I have to, to get my code working correctly ), and I can output to the console that Bmax initializes quite nicely using the <iostream> functions. I'm sure delphi will be able to do the same.

Last edited 2012


WPOSTMA(Posted 2012) [#10]
I thought i added this but i guess i did not, i am already using the stdcall function because i heard it lets me use my functions with other languages other than delphi. and by sending a message to the screen, i meant an alert or the same thing that the BMX Notify command does. (i am just using that example dll to get this dll thing working)


col(Posted 2012) [#11]
I use .dlls all the time so this is probably one of these little things thats gets overlooked and you up bald through pulling your hair out!

In my current project im calling into c++ which calls back into bmax which calls a .dll loaded function and passes the result back into c++ which passes a different result back into bmax! So I know pretty much anything can be done with BMax, its justs a case of learning the nuances to get things working harmoniously.

Keep it simple at first and try sending a bog standard integer variable value into the dll and return the same value, then try passing other datatypes floats and/or doubles etc. then pass an array then a string, then a bmax type etc.

I've just had a thought regarding the string in the delphi code. Strings always seems to handled differently in all the languages! So I'd definately suspect that at the moment.

I still recommend starting small ( ints, floats etc ) passing values back and forth then work your way up to the other datatypes. It shouldnt take long at all but you'll get to know any quirks very quickly.