Blitz3D+ Command Reference

CallDLL ( dll_name$,func_name$[,in_bank][,out_bank] )

Parameters

dll_name$ - name or path of the DLL to load

func_name$ - name of the exported function to call, spelled exactly as the DLL exports it

in_bank (optional) - bank holding the data to send; 0 sends nothing (default)

out_bank (optional) - bank for the function to write its answer into; 0 receives nothing (default)

Description

Calls a function in a Windows DLL, passing banks in and out.

This is the quick way to borrow code that Blitz3D does not have - a physics helper, an encryption routine, a bit of hardware access - without building a full userlib. The DLL is loaded, the named export is called, and the DLL is unloaded again, all inside the one command. The function's return value comes back as CallDLL's result.

The function on the C side has to have exactly this shape and no other parameters:

int __cdecl MyFunction( const void *in,int in_size,void *out,int out_size )

Everything you send goes in in_bank and everything you get back arrives in out_bank, so structure your data with PokeInt, PokeFloat and friends and read it out with the Peek family. Both banks are optional; leaving one out passes a null pointer and a size of zero.

The gotcha that catches everyone is the return value. CallDLL answers 0 when the DLL cannot be loaded, 0 when the DLL loads but has no such export, and 0 when a successful call simply returns 0 - the three are indistinguishable. Nothing raises an error, which is friendly but silent, so check the file yourself with FileType first and design your function to return something that is never 0 on success.

Two more things to know. The name is handed straight to Windows, so put the DLL next to your program or pass a full path - the userlibs folder is not searched, and the DLL must match the runtime's architecture, meaning a 64-bit build loads only 64-bit DLLs. And the library is loaded and freed on every call, so this is not the place for per-frame work.

If you own the library and want more than one function, or want real typed parameters instead of a bank of bytes, the .decls userlib mechanism is the better tool: drop the DLL and a declarations file into the userlibs folder and its exports become ordinary Blitz commands. That path checks the DLL's architecture before loading it and gives a clear error if it is wrong. The full spec is in userlibs/UserLibs.txt. CallDLL also cannot be used inside a Worker Function - jobs run away from the main runtime.

See also: CreateBank, PokeInt, PeekInt, BankSize, FileType, SystemProperty.

Example

; CallDLL Example
; ---------------

; CallDLL hands a block of bytes to a function inside a Windows DLL and
; lets it write a block of bytes back. The function has to look exactly
; like this on the C side, and take no other parameters:
;
;   int __cdecl MyFunction(const void *in,int in_size,void *out,int out_size)

; The request we would send - a couple of numbers in a bank
request=CreateBank(8)
PokeInt request,0,1234
PokeInt request,4,5678

; Somewhere for the DLL to write its answer
reply=CreateBank(8)

Print "in_bank  "+BankSize(request)+" bytes, holding "+PeekInt(request,0)+" and "+PeekInt(request,4)
Print "out_bank "+BankSize(reply)+" bytes, waiting to be filled"
Print ""

; Case one: the DLL is not installed. CallDLL answers 0 instead of
; raising an error, so a missing plug-in cannot crash your game.
missing=CallDLL("no_such_library.dll","AnyFunction",request,reply)
Print "DLL not installed          -> "+missing

; Case two: a DLL that really is there, asked for a function it does
; not export. kernel32 ships with Windows and is already loaded, so
; this is completely safe to try.
system_dir$=SystemProperty("systemdir")
wrong=CallDLL(system_dir+"\kernel32.dll","BlitzDemoEntryPoint",request,reply)
Print "DLL found, export missing  -> "+wrong

; Both banks are optional - leave them out for a call that needs no data
none=CallDLL("no_such_library.dll","AnyFunction")
Print "Called with no banks       -> "+none

Print ""
Print "Every miss answers 0, and so does a successful call that happens"
Print "to return 0, so CallDLL cannot tell you which one happened. Test"
Print "the file yourself first: FileType() says whether it is there."
Print ""
Print "no_such_library.dll FileType = "+FileType("no_such_library.dll")+"  (0 means no such file)"
Print "kernel32.dll FileType        = "+FileType(system_dir+"\kernel32.dll")+"  (1 means a file)"

Print ""
Print "The DLL must match the runtime - a 64-bit build loads only 64-bit"
Print "DLLs - and the name goes straight to Windows, so ship the DLL"
Print "beside your program or pass a full path. CallDLL does not look"
Print "in the userlibs folder."
Print ""
Print "For a real library the .decls userlib mechanism is usually the"
Print "better tool: it binds named exports as ordinary Blitz commands"
Print "with proper parameters. See userlibs/UserLibs.txt."

FreeBank request
FreeBank reply

Print ""
Print "Press any key to close the example"
WaitKey

End

Index