%DLL_CALL

Call a DLL routine

WSupported on Windows
USupported on Unix

 

NSupported in Synergy .NET
value = %DLL_CALL(dll_handle, [convention], func_name[, arg, ...]) 

value

The return value of the DLL function as an integer data type. (^VAL)

dll_handle

The handle of the DLL, as returned from %DLL_OPEN. (i)

convention

One of the following calling conventions: (n)

DLL_TYPE_C

Use C calling convention.

DLL_TYPE_DBLCALL

Use Synergy runtime-compatible calling convention (C). (traditional Synergy)

DLL_TYPE_FASTCALL

Use __fastcall calling convention.

DLL_TYPE_STDCALL

Use __stdcall calling convention.

DLL_TYPE_WINAPI

Use WINAPI calling convention.

func_name

The name of the function to be called within the DLL. (a)

arg

(optional) One or more variables used to pass alpha or integer data types to the function in the DLL. Integer arguments can be one, two, or four bytes long (or eight bytes on 64-bit systems).

Discussion

The %DLL_CALL function calls a subroutine or function in a DLL.

Before invoking %DLL_CALL, check the documentation for your DLL to learn how the function is declared, which data type the function returns, which calling convention to use, and which arguments are necessary. If you call a DLL subroutine with improper arguments, the result is undefined. The Declaring variables based on argument expected table and Declaring variables based on return value table provide additional information about the return value of the DLL function and the arguments expected by the DLL function.

DLL_TYPE_C and DLL_TYPE_DBLCALL are the only calling conventions available on Unix. The default calling convention on Unix is DLL_TYPE_C. The default calling convention on Windows is DLL_TYPE_STDCALL.

Note

DLL_TYPE_STDCALL and DLL_TYPE_WINAPI are interchangeable.

A DLL may require an underscore as a prefix to the function name. In such a case, func_name must have an underscore as its first character as well. For example:

_example

You can pass up to 20 arg variables. The number and type of arg variables depends on the number and type that the DLL function expects. These arg variables are automatically converted from Synergy DBL descriptors into C data types of four-byte integers, pointers, or null-terminated strings for use by the DLL. %DLL_CALL only passes the number of arguments specified.

Note

Arg cannot be passed as a numeric literal. If passed as a numeric literal, it is handled as a decimal, which is not supported. To pass a literal value, use %integer(value, 4). See Examples.

Use ^ADDR as an arg variable to create a pointer to obtain the address of a Synergy DBL variable. (See ^ADDR for more information.)

Passing an alpha variable to a DLL routine (without using ^ADDR) converts the alpha to a null-terminated C string. On return, the string data is automatically copied back to the alpha variable.

If the DLL function modifies an alpha argument, the modified string overwrites the unmodified string. If the modified string is longer than the unmodified string, the modified string is truncated.

The following table lists how a variable should be declared in Synergy DBL based on the argument expected by the DLL function. The “Argument expected by the DLL function” column lists the argument types. The “Variable declared in Synergy” column shows which Synergy data types are allowed for the argument types.

Declaring variables based on argument expected

Argument expected by the DLL function

Variable declared in Synergy

int, dword

int

long, long int, unsigned long

int (Windows) or i8 (Unix)

__int64 i8 or long

int *, void *, any other pointers (except pointers to null-terminated character strings)

^ADDR()

char *, null-terminated character string

a

short, short int, unsigned short, word

short – Use %UNSIGNED for unsigned short

char, unsigned char, byte

sbyte – Use %UNSIGNED for unsigned char

int **, void ** (pointer to a pointer)

^ADDR(D_ADDR-defined variable)

char ** (pointer to a pointer)

^ADDR(D_ADDR-defined variable) – To access the returned string, use %MEM_PROC to register the address (D_ADDR) as a memory handle

HANDLE HWND D_ADDR
LPCSTR a

The table below lists how a variable should be declared in Synergy DBL based upon the return value of the DLL function. The “Return value of the DLL function” column lists the return value types. The “Variable declared in Synergy” column shows which Synergy data type to declare for the return value.

Declaring variables based on return value

Return value of the DLL function

Variable declared in Synergy

int

i4 (int)

long, unsigned long

int (Windows) or i8 (Unix) – Unsigned long is accessed in Synergy DBL as %UNSIGNED

long long, __int64 i8

short int

i2 (short)

unsigned short

i2 (short) – Accessed in Synergy DBL as %UNSIGNED

char

a1 or i1

unsigned char

i1 – Accessed in Synergy DBL as %UNSIGNED

int *, char *, any other pointers (including null-terminated character strings)

D_ADDR

On Windows, %SYSERR is updated from the GetLastError value after every %DLL_CALL. You cannot call GetLastError directly, as the value is overwritten in making the call.

Examples

The following example uses %integer(0,4) to pass an integer 0:

record   
    dllhandle   ,i4 
    ret         ,i4 
    text        ,a40    ,"This is the text"
    title       ,a40    ,"This is the title"

proc   
;Open the 32-bit DLL. It is part of Win32s
    dllhandle = %dll_open("user32.dll")
    ret = %dll_call(dllhandle, DLL_TYPE_WINAPI, "MessageBoxA", 
&         %integer(0, 4), text, title, %integer(0, 4))
;For details on "MessageBoxA" check your Windows API doc
;Using XCALL
    xcall dll_call(dllhandle, DLL_TYPE_WINAPI, "MessageBoxA", 
&         %integer(0, 4), text, title, %integer(1, 4))
    ret = %dll_close(dllhandle)                 ;Close the DLL
end 

Pointers as return values

Some DLL functions return a pointer to a variable. In order to access that variable, the Synergy DBL program has to de-reference the pointer. De-referencing is the inverse operation to ^ADDR and can be accomplished using Synergy DBL’s dynamic memory management routines. Only pointers that are returned by DLL functions can be de-referenced and used by a Synergy program.

The following example illustrates how to de-reference the pointer:

struct data {   
     long int num1;   
     char text[100]; }      //The struct may contain any datatype.
                                 // When calling 16-bit DLLs, pointers are 
                                 // not allowed as structure members.
struct data *examplefunc5(long arg1);  
struct data **examplefunc6(long arg1);

Calling a DLL from Synergy DBL:

structure datastruct                     ;Describes layout of data record.
     num1               ,i4
     text               ,a100
record   
     mem_hand           ,i4
     dll_hand           ,i4
     pointer            ,D_ADDR
     arg1               ,i4
     retsts             ,i4
record datarec   
     number             ,i4
     str                ,a100

;The DLL function returns a pointer to the struct called data.
     pointer = %dll_call(dll_hand,, "examplefunc5", arg1)
;Alternative: The DLL function returns a pointer to a pointer.
     retsts = %dll_call(dll_hand,, "examplefunc6", arg1)

;First step: DM_REG converts the returned pointer to a Synergy DBL   
; memory handle.
     mem_hand = %mem_proc(DM_REG, 104, pointer)
                                        ;104 is size of struct data in bytes.

;Second step: ^m() converts the memory handle to a usable Synergy DBL
; record.
     datarec = ^m(datastruct, mem_hand) ;Datastruct tells ^m() about expected data layout.
     writes(1, %string(datarec.number))
     writes(1, datarec.str)

For another example, see SampleDLL, available from Synergy CodeExchange in the Synergex Resource Center.

Passing structured data types

Structured data types can be passed to a DLL function by reference. To do so, a corresponding record must be declared in the Synergy application. In the function call %DLL_CALL, ^ADDR is used to obtain a reference to a record.

The following example shows how to pass a pointer to a structured data record as an argument to a DLL function:

struct data {
     int num1; 
     char text[100]; }          //The struct may contain any data types
long int CDECL examplefunc4(struct data *arg1);
record datarec
     num1       ,i2
     text       ,a100
retlong = %dll_call(dllhandle,, "examplefunc4", ^addr(datarec))
                                ;retlong declared as i4