An EXE has two basic sources for executable code. The code can be compiled within the EXE or it may exist in a completely separate file. Such separate files are called dynamic link libraries (DLLs).
Inside a DLL you will find the usual programming constructs - variables and procedures (Sub/Functions). DLLs can allow a procedure to be accessed by an external application or by another DLL. Such procedures are said to be exported.
Not all procedures within a DLL have to be exported. Instead, they may be kept private and are not available to any external executable applications or DLLs. It is common practice for DLLs to have both private and exported procedures.
Knowing the DLL file name and the name of the exported procedure, an application can execute the code within the DLL as though it had been compiled within the executable.
Creating a (Useless) DLL
As noted above, a DLL consists of familiar programming variables and procedures (Sub/Functions), although the syntax varies a bit from that of a standard executable program.
The following single line of code can actually create a DLL.
#COMPILE DLL 'directs compiler to create DLL
When compiled in the IDE, this line creates a DLL but it has no variable and no procedures - exported or private. Not very useful, but does serve to demystify the creation of a DLL. The PowerBASIC compiler handles all the details - all the programmer has to provide is the source code.
Creating a Simple DLL
Here's a slightly more complicated DLL. In this case, the DLL contains a single exported procedure called RandomAdd which simply adds a random amount to the value of the variable x. The result is returned to the calling program. In this example, the DLL has no other variables or procedures (private or exported).
#COMPILE DLL 'directs compiler to create DLL FUNCTION RandomAdd ALIAS "RandomAdd" (BYVAL x AS Long) EXPORT AS Long Randomize Timer RandomAdd = x + RND * 100 'adds random amount to x END FUNCTION
And here's a PowerBASIC program which uses the DLL. In this example, the DLL was compiled to a file called temp5.dll. This example uses a Declare statement to link to the DLL, as was discussed in the API tutorial section dealing with linking to external DLLs.
#Compile Exe Declare Function RandomAdd Lib "temp5.dll" Alias "RandomAdd" (ByVal x&) As Long Function PBMain () As Long Dim a As Long,b As Long a = RandomAdd(b) MsgBox a End Function
This code, when compiled, creates a PowerBASIC EXE that accesses the DLL procedure to add a random amount (1-100) to the value it is given. The result is displayed in a MsgBox. Still not very useful, but shows the complete cycle of creating and using a DLL with PowerBASIC.
When a DLL is loaded into memory, Windows automatically calls a function called LIBMAIN, if it exists. The use of LIBMAIN in your code is optional.
DLL Project Template
The PowerBASIC IDE menu selection File >> "DLL Framework Using LIBMAIN" creates a new DLL project and preloads the following source code:
#Compile Dll #Dim All %USEMACROS = 1 #Include "Win32API.inc" Global ghInstance As Dword Function LibMain (ByVal hInstance As Long, _ ByVal fwdReason As Long, _ ByVal lpvReserved As Long) As Long Select Case fwdReason Case %DLL_PROCESS_ATTACH 'Indicates that the DLL is being loaded by another process (a DLL 'or EXE is loading the DLL). DLLs can use this opportunity to 'initialize any instance or global data, such as arrays. ghInstance = hInstance Function = 1 'success! 'FUNCTION = 0 'failure! This will prevent the EXE from running. Case %DLL_PROCESS_DETACH 'Indicates that the DLL is being unloaded or detached from the 'calling application. DLLs can take this opportunity to clean 'up all resources for all threads attached and known to the DLL. Function = 1 'success! 'FUNCTION = 0 'failure! Case %DLL_THREAD_ATTACH 'Indicates that the DLL is being loaded by a new thread in the 'calling application. DLLs can use this opportunity to 'initialize any thread local storage (TLS). Function = 1 'success! 'FUNCTION = 0 'failure! Case %DLL_THREAD_DETACH 'Indicates that the thread is exiting cleanly. If the DLL has 'allocated any thread local storage, it should be released. Function = 1 'success! 'FUNCTION = 0 'failure! End Select End Function
If you have any suggestions or corrections, please let me know.