Calling Conventions in BCX
C_DECLARE statement
Purpose:
The BCX statement
C_DECLARE
provides a function declaration specification that allows
the function to be used with the _cdecl calling convention.
Syntax 1: C_DECLARE [ SUB | FUNCTION ] ProcName(Paramlist) |
Syntax 2: C_DECLARE [ SUB | FUNCTION ] ProcName$ _ LIB "DllName.Dll" _ ALIAS "ProcName" _ (Paramlist) |
Remarks:
C_DECLARE is used to expose SUBs and FUNCTIONs that have been exported in an External Dynamic Link Library(DLL) as well as SUBs and FUNCTIONs that have been compiled and placed in .obj files or libraries.
The Paramlist follows the same rules as when declaring variables in a normal SUB or FUNCTION declaration. The variables used in the Paramlist are dummies but must communicate the data type, either by using its abbreviated type identifier($%!#) or using the AS clause.
_cdecl is the default C calling convention. The stack is cleaned up by the calling function, so vararg functions can be used. Arguments are pushed on the stack from right to left.
C_DECLARE adds the prototypes to the C code, plus it allows you to declare the function *type* AND its arguments using BASIC syntax, instead of C.
C_DECLARE is not compatible with LoadLibrary If LoadLibrary is to be used then DECLARE must be used as the declaration specification for the functions in the DLL.
For example ...
C_DECLARE FUNCTION FOO(A AS UINT) AS INTEGER
translates to C code
int __cdecl FOO(UINT);
which will not work with LoadLibrary.
Instead, you would need to inline:
int(*FOO)(UINT);
Optional arguments are allowed, although not all compilers support optional arguments for syntax 2. The OPTIONAL keyword is not needed and should not be used.
Both Syntax 1 and Syntax 2 of C_DECLARE support variable arguments(...).
BCX Console Sample Programs using C_DECLARE statement. S123.bas Also study the many examples in the DLL_Demo folder of the BCX distribution.
DECLARE statement
Purpose:
The BCX statement DECLARE
provides a function declaration specification that allows the function
to be used with the _stdcall calling convention.
Syntax 1: DECLARE [ SUB | FUNCTION ] ProcName(Paramlist) |
Syntax 2: DECLARE [ SUB | FUNCTION ] ProcName$ _ LIB "DllName.Dll" _ ALIAS "ProcName" _ (Paramlist) |
Remarks:
Optional arguments are allowed, although not all compilers support optional arguments for syntax 2. The OPTIONAL keyword is not needed and should not be used.
Once you C_DECLARE or DECLARE a SUB or FUNCTION -correctly- inside your program, you can call it from any other SUB or FUNCTION. In a -CONSOLE- app, you can place DECLARE statements anywhere in your source program.
In a -GUI- program, you must place it a SUB or FUNCTION so that the initialization code has some place valid to run. The smart place to put your DECLARE in a GUI is inside your WinMain FUNCTION -- or if you are using the simplified BCX_XXXXX GUI commands, inside the FormLoad SUB.
In a -DLL- app, you should probably place your DECLARE inside DllMain.
Here is a complete example which calls a DLL function
which returns a string.
The example is in three sections, the DLL, a program to call the function from
the DLL and a batch file to compile the programs.
The first section is the BCX DLL code. Cut and save this as RESPOND.BAS
$DLL STDCALL FUNCTION Respond(Buf$) EXPORT Buf$ = Buf$ & " The Eagle has landed" FUNCTION = LEN(Buf$) END FUNCTION
The second section is the program which will call the function in the DLL. Cut and save this as TESTDLL.BAS
DIM a$, l DECLARE FUNCTION Respond LIB "respond.dll" ALIAS "Respond"(foo$) AS INTEGER a$ = "Boy Howdy" l = LEN(a$) ? l;" ";a$ l = Respond(a$) ? l;" ";a$ getchar()
Here, in the third section, is a batch file to translate, compile and link the RESPOND.BAS and TESTDLL.bas.
If Pelle's C is used as the compiler, cut and save the following as BUILD.BAT
BC Respond POCC /Ze /Gn Respond.c POLINK /dll Respond.obj BC TestDLL POCC /Gd /Ze TestDLL.c POLINK TestDLL.objThe PLAYWAV example also demonstrates the use of
DECLARE
and, as well, how calls are made to a
DECLARE
d function.
LIB statement
Purpose: BCX provides a universal method for calling both _stdcall and _cdecl DLL functions irrespective of the differences between the two calling conventions.
Syntax: [RetVal =] DLLFunction(LIB "DLLName[.dll]" [, Parameters, ...]) Parameters:
|
Unlike the conventional DECLARE and C_DECLARE statements, the dynamic DLL function calling engine provides the following advantages:
To be able to ensure this non-language-specific flexibility, the DLLs being called should meet the following reasonable requirements:
The overwhelming majority of commonly used Windows API, VisualBasic, Delphi, and third-party DLLs are based on these simple rules.
Note well that while the DECLARE/C_DECLARE convention is still supported by BCX for backward compatibility reasons, both conventions should not be used simultaneously in the same code because this will render the dynacall engine's memory management facilities ineffective.
Example 1 :
MessageBox(LIB "user32", NULL, "Your Title", "Your Msg", MB_OK)
Example 2 :
SetWindowText(LIB "user32", FindWindow(LIB "user32", "Notepad", 0L), "Hello = !")
BCX_DYNACALL procedure
Purpose: BCX_DYNACALL
is a user accessible runtime variant of the
of the BCX translator internally used BCX_DynaCall function. This user accessible variant
provides, for the user, an easier runtime execution of functions not known at compile time.
Syntax: [RetVal =] Parameters:
|
Remarks: This variation is mainly to allow a user's program to have the ability to setup functions at runtime. For instance, the functions could be read from a configuration file. The easiest way is just to define an array that is equal or greater than the maximum number of arguments that a function may use. The arguments are then, and must be, cast as integer.
Example:DIM
AnyType[
4
]
AS
INTEGER
AnyType[
0
]
=
(
INTEGER
)
NULL AnyType[
1
]
=
(
INTEGER
)
"Your Title"
AnyType[
2
]
=
(
INTEGER
)
"Your Msg"
AnyType[
3
]
=
(
INTEGER
)
MB_OKBCX_DynaCall
(
"user32"
,"MessageBox"
,4
, AnyType)
STDCALL statement
Purpose: STDCALL is a reserved BCX keyword used in two different contexts.
Remarks:
Win32 API functions and user-defined callbacks use the _stdcall calling convention. _stdcall is used as well by Visual BASIC, and Delphi. When _stdcall is used, the stack is cleaned up by called function, so compiler makes vararg functions cdecl, and a function prototype is required. Arguments pushed on stack right to left.
Syntax 1: $DLL STDCALL |
Syntax 2: SUB Foo(Bloof AS DOUBLE) STDCALL |