define_c_func

Definition: integer rid = define_c_func(object lib, object fname, sequence args, atom return_type)
Description: Define the characteristics of a C function that you wish to call from your Phix program. A small integer, known as a routine id , is returned, or -1 if the function cannot be found.

The define_cffi_func routine is a string-based wrapper of this routine, which you may find easier to use.

lib is either an (atom) address returned by open_dll(), or {}.
if lib is an atom, fname is the (string) name of a function within that dll, optionally as either {'+',"name"} or "+name" to specify the CDECL calling convention.
if lib is {}, fname is the (atom) address of a machine code function, optionally as {'+',addr} to specify the CDECL calling convention.

CDECL is the default/only calling convention on a Linux system.
STDCALL is the default in a Windows system.
The CDECL convention requires the callee to clean up the stack, and is therefore more suited to variable numbers of arguments, whereas with STDCALL the routine cleans up the stack before returning.

args is a list of the parameter types for the function.
return_type should be self explanatory. The following C types are predefined (in psym.e/syminit):
                    C_BYTE = #01000001,     -- an 8 bit signed integer
                    C_CHAR = C_BYTE,
                   C_UCHAR = #02000001,     -- an 8 bit unsigned integer
                   C_UBYTE = C_UCHAR,
                   C_SHORT = #01000002,     -- a 16 bit signed integer
                    C_WORD = C_SHORT,
                  C_USHORT = #02000002,     -- a 16 bit unsigned integer
                     C_INT = #01000004,     -- a 32 bit signed integer
                    C_BOOL = C_INT,
                    C_UINT = #02000004,     -- a 32 bit unsigned integer
                   C_INT64 = #01000008,     -- a 64 bit signed integer
                   C_QWORD = #02000008,     -- a 64 bit unsigned integer
                    C_LONG = C_INT,
DEV: -- also C_WPARAM, C_LPARAM, C_HRESULT
                   C_ULONG = C_UINT,
                   C_DWORD = C_UINT,
                 C_POINTER = iff(machine_bits()=32?#02000004    -- a 32 bit (unsigned) pointer
                                                  :#01000008)   -- a 64-bit (signed) pointer
                     C_PTR = C_POINTER,
                  C_HANDLE = C_PTR,
                    C_HWND = C_PTR,
                   C_FLOAT = #03000004,     -- a 32-bit float
                  C_DOUBLE = #03000008      -- a 64-bit float
Comments: The resulting routine id , rid, can be passed to c_func() when you want to call the C function.

You can pass or return any C integer type or pointer type. You can also pass a phix atom as a C double or float, and get a C double or float returned to you as a phix atom.

In C (on Windows and Linux), parameter types which use 4 bytes or less are all passed the same way, so it is not necessary to be exact. However the distinction between signed and unsigned may be important when you specify the return type of a function.

Currently, there is no way to pass a C structure by value or get a C structure as a return result. You can only pass a pointer to a structure and get a pointer to a structure as a result.

If you are not interested in using the value returned by the C function, you should instead define it with define_c_proc() and call it with c_proc().

The C type "long double" should be avoided at all costs - it is highly compiler-dependent and can be 10/8/12/16 bytes aligned to an 8/2/4/16 byte boundary.
Example:
atom user32
integer LoadIcon
-- open user32.dll - it contains the LoadIconA C function
user32 = open_dll("user32.dll")
-- It takes a C pointer and a C int as parameters.
-- It returns a C int as a result.
LoadIcon = define_c_func(user32, "LoadIconA",
                         {C_POINTER, C_INT}, C_INT)
if LoadIcon=-1 then
    puts(1, "LoadIconA could not be found!\n")
end if
See Also: c_func, define_cffi_func, define_c_proc, c_proc, open_dll, Calling C Functions