Creating a DLL

$DLL directive

Purpose: The $DLL directive tells BCX to generate code for creating a "C" source code file for a Dynamically Linked Library that follows the _cdecl calling convention used by most C and C++ compilers.

When creating a dynamically linked library that is to be called from an executable created with BCX, $DLL must be the first line in your source code file.

EXPORT qualifier

The EXPORT qualifer must be used by any SUB or FUNCTION to be called from a DLL by an external program. If a SUB or FUNCTION will be used only within the DLL, the EXPORT qualifer is not to be used. The EXPORT qualifier is to be used in both _cdecl and _stdcall DLLs and only in a SUB or FUNCTION that the programmer wants to expose to other programs.

Example 1: The example below will load and use an integer function from a DLL. It 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. Copy and save this as C_DLL.bas


 $DLL STDCALL 'Must be the first statement 
 
 FUNCTION SQUARED(A) EXPORT
  FUNCTION = A * A
 END FUNCTION

The second section is the program which will call the function in the DLL. Copy and save this as TestC_DLL.bas.


 DECLARE FUNCTION Squared% LIB "C_DLL.dll" ALIAS "SQUARED" (A AS INTEGER)
 
 DIM i AS INTEGER
 
 FOR i = 1 TO 10
  PRINT i, " Squared =", Squared(i)
 NEXT
 
 PRINT ""
 PAUSE

Here, in the third section, is a batch file to translate, compile and link the C_DLL.lib and TestC_DLL.bas. Copy and save this as BuildC_DLL.bat and run it to compile the example.


 CALL povars32.bat
 bc C_DLL
 pocc -W1 -Gd -Gn -Go -Ze -Zx -Tx86-coff C_DLL.c
 polink -dll -machine:ix86 -subsystem:console -OUT:C_DLL.dll C_DLL.obj
 bc TestC_DLL
 pocc -W1 -Gd -Go -Ze -Zx -Tx86-coff TestC_DLL.c
 polink -release -machine:ix86 -subsystem:console -OUT:TestC_DLL.exe TestC_DLL.obj C_DLL.lib 

Result:


  1 squared = 1  
  2 squared = 4  
  3 squared = 9  
  4 squared = 16 
  5 squared = 25 
  6 squared = 36 
  7 squared = 49 
  8 squared = 64 
  9 squared = 81 
 10 squared = 100

A SUB or FUNCTION using the EXPORT qualifier will cause BCX to emit the appropriate prototype (cdecl or stdcall) that will allow the procedure to be called internally within the DLL module and, as well, externally by the calling process, which is usually an .EXE but also can be another DLL.

The following project demonstrates an example of this, where the FUNCTION XXUCASE$ is used internally in the MyDLL.dll by XUCASE$ and, as well, the FUNCTION XXUCASE$ is used externally by TestMyDLL.Bas.

Example 2: This first portion is the DLL code. Copy and save this as MyDLL.bas.


 $DLL STDCALL

 FUNCTION XUCASE$(A$) EXPORT
  FUNCTION = XXUCASE$(A$)
 END FUNCTION

 FUNCTION XXUCASE$(A$) EXPORT
  FUNCTION = UCASE$(A$)
 END FUNCTION

This is a demo program which will load and use MyDLL.dll. Copy and save this as Test_MyDLL.bas.


 DECLARE FUNCTION XUCASE$ LIB "MyDLL.DLL" ALIAS "XUCASE"(A$)
 DECLARE FUNCTION XXUCASE$ LIB "MyDLL.DLL" ALIAS "XXUCASE"(A$)

 PRINT "TESTING XUCASE$: ", XUCASE$("hello")
 PRINT "TESTING XXCASE$: ", XXUCASE$("hello")

Here is a batch file to translate, compile and link the MyDLL.lib and Test_MyDLL.bas. Copy and save this as Build_MyDLL.bat and run it to compile the example.

 
 CALL povars32.bat
 bc MyDLL
 pocc -W1 -Gd -Gn -Go -Ze -Zx -Tx86-coff MyDLL.c
 polink -dll -release -machine:ix86 -subsystem:windows MyDLL.obj -OUT:MyDLL.dll 
 bc Test_MyDLL
 pocc -W1 -Gd -Go -Ze -Zx -Tx86-coff Test_MyDLL.c
 polink -release -machine:ix86 -subsystem:console Test_MyDLL.obj -OUT:Test_MyDLL.exe

$DLL STDCALL directive

The $DLL directive can be specified with the optional STDCALL argument, $DLL STDCALL which tells BCX to generate a "C" source code file for a dynamically linked library that conforms to the _stdcall calling convention used by Visual BASIC and some other compilers.

When compiling with the

an export file named "ProgramName.def" will be generated in addition to the normal BCX translator output.

Example 1: This first portion is the DLL code. Copy and save this as STDCALL_DLL.bas.


 $DLL STDCALL

 FUNCTION WORLD$(A$) EXPORT
  LOCAL T$
  T$ = A$ & ",World"
  T$ = UCASE$(T$)
  FUNCTION = T$
 END FUNCTION

This is a demo program which will load and use a string function from the STDCALL_DLL. Copy and save this as Test_STDCALL_DLL.bas.


 DECLARE FUNCTION Up$ LIB "STDCALL_DLL.dll" ALIAS "WORLD"(Param$)

 PRINT "Dll Result is: ", Up$("hello")

Here is a batch file to translate, compile and link the STDCALL_DLL.lib and Test_STDCALL_DLL.bas. Copy and save this as Build_STDCALL_DLL.bat and run it to compile the example.


 CALL povars32.bat
 bc STDCALL_DLL
 pocc -W1 -Gd -Gn -Go -Ze -Zx -Tx86-coff STDCALL_DLL.c
 polink -dll -release -machine:ix86 -subsystem:windows STDCALL_DLL.obj -OUT:STDCALL_DLL.dll 
 bc Test_STDCALL_DLL
 pocc -W1 -Gd -Go -Ze -Zx -Tx86-coff Test_STDCALL_DLL.c
 polink -release -machine:ix86 -subsystem:console Test_STDCALL_DLL.obj -OUT:Test_STDCALL_DLL.exe

Example 2: This is an example which shows how a dll can call a callback function in an application. The first portion is the DLL code. Copy and save this as CALLBACK_DLL.bas.


 $DLL STDCALL
 
 FUNCTION MyDllFunction(x$, foo(b, a$) AS FUNCTION BOOL CALLBACK) AS BOOL EXPORT
  DIM z$
  z$ = LCASE$(x$)
  IF foo(1, z$) = TRUE THEN MSGBOX "foo is true"
  FUNCTION = TRUE
 END FUNCTION

Copy and save the following as Test_CALLBACK_DLL.bas. This is a demo program which will load the CALLBACK_DLL and have the dll call a callback function in the Test_CALLBACK_DLL.exe.


 MyDllFunction (LIB "CALLBACK_DLL.dll", "little lamb", MyFoo)
 
 PAUSE
 
 FUNCTION MyFoo(a%, cc$) AS BOOL STDCALL
  PRINT a%, " ", cc$
  FUNCTION = TRUE
 END FUNCTION

Here is a batch file to translate, compile and link the CALLBACK_DLL.lib and Test_CALLBACK_DLL.bas. Copy and save this as Build_CALLBACK_DLL.bat and run it to compile the example.


 CALL povars32.bat
 bc CALLBACK_DLL
 pocc -W1 -Gd -Gn -Go -Ze -Zx -Tx86-coff CALLBACK_DLL.c
 polink -dll -release -machine:ix86 -subsystem:windows CALLBACK_DLL.obj -OUT:CALLBACK_DLL.dll 
 bc Test_CALLBACK_DLL
 pocc -W1 -Gd -Go -Ze -Zx -Tx86-coff Test_CALLBACK_DLL.c
 polink -release -machine:ix86 -subsystem:console Test_CALLBACK_DLL.obj -OUT:Test_CALLBACK_DLL.exe

For many more DLL example programs see the \BCX\DLL_Demo directory in the BCX distribution.

$NODLLMAIN directive

Purpose: The $NODLLMAIN directive causes BCX to create a DLL without the DllMain code that BCX normally adds to a DLL. This allows a custom DllMain to be used.

The $NODLLMAIN directive must precede the $DLL directive in the source code file.

Here is a template for a DllMain function.


 FUNCTION DllMain(hInst AS HINSTANCE, _
                     Reason AS DWORD, _
                  Reserved AS LPVOID) EXPORT

  SELECT CASE Reason
   '************************************************************** 
   CASE DLL_PROCESS_ATTACH
   ' < -- Do our initializations here  -- > 
   MSGBOX "Your DLL has been loaded"
   '************************************************************** 
   CASE DLL_PROCESS_DETACH, DLL_THREAD_ATTACH, DLL_THREAD_DETACH
  END SELECT
 
  FUNCTION = TRUE
 END FUNCTION