%DLL_CALL
WTSupported in traditional Synergy on Windows
|
WNSupported in Synergy .NET on Windows
|
USupported on UNIX
|
|
value = %DLL_CALL(dll_handle, [convention], func_name[, arg, ...])
Return value
value
The return value of the DLL function as an integer data type. (^VAL)
Arguments
dll_handle
The handle of the DLL, as returned from %DLL_OPEN. (i)
convention
One of the following calling conventions: (n)
Use C calling convention.
Use Synergy runtime-compatible calling convention (C). (traditional Synergy)
Use __fastcall calling convention.
Use __stdcall calling convention.
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.
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.
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.
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.
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) |
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.
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