A DLL is Microsoft’s way of implementing a code library that multiple programs can use. Unlike executable programs, DLL files can’t be run directly but must be called upon by other code. These libraries usually have the file extension DLL, OCX, or DRV. There are several advantages to using DLLs –
- DLLs can reduce the duplication of code when a different program uses the same code library
- Easy deployment and installation. For instance, when multiple programs use the same DLL, those programs will all benefit from the same update or fix.
- DLLs help with modular programming enabling a program to be split into smaller tasks.
Implementing a DLL
Any function within a DLL that will be called outside the DLL must be exported. Any DLL function being called by a client program must be imported. Functions for import or export are declared using the _declspec keyword followed by storage-class attributes in parenthesis (dllimport and dllexport) and then the function name.
Each function for export is declared as follows
__declspec(dllexport) void functionname()
Functions for import are declared as follows
__declspec(dllimport) void functionname()
A simple DLL
The example below illustrates a simple DLL file consisting of one function and a messagebox routine. When the DLL is compiled it will produce two files: one with a .dll extension and one with a .lib extension. The .dll file must be in a directory where the application can find it. Windows will search in the current application directory, the working directory, the standard DLL directory, and finally directories specified in the path variable.
#include <windows.h>
extern "C" __declspec(dllexport) void msgfunct()
{
MessageBox( NULL, TEXT("Hello World"), TEXT("In a DLL"), MB_OK);
}
The optional declaration extern “C” enables a library to be shared between C and C++. This is necessary so that the C++ compiler does not add any extra mangling information during compilation
Linking to a DLL
There are two ways to load a DLL: implicit linking and explicit linking
Implicit linking is when the operating system loads the DLL simultaneously as the executable file. The client program then calls the exported functions in the DLL the same way it would for those within the executable. The client program must link to the DLL .lib file. In visual C++ this can be done within Project/Settings/link option or by adding a #pragma directive (see below)-
The following example illustrates a simple dll file that contains a simple message box function. The function when imported and executed displays the messagebox.
#pragma comment(lib, "exampleDLL.lib")
extern "C" __declspec(dllimport) void msgfunct();
int main(int argc, char* argv[])
{
msgfunct();
return 0;
}
Explicit Linking – here the operating system loads the DLL at runtime. An executable that uses a DLL by explicit linking, must load and unload the DLL. Access to the DLL function is via a pointer.
The following example illustrates a simple console exe file that imports and calls a simple dll function, from the dll file exampleDLL.dll (above)
typedef VOID (*DLLPROC) ();
DLLPROC HelloWorld;
int main(int argc, char* argv[])
{
DLLPROC HelloWorld;
HINSTANCE hInstLibrary = LoadLibrary("exampleDLL.dll");
if (hInstLibrary)
{
HelloWorld = (DLLPROC) GetProcAddress(hInstLibrary, "msgfunct");
if (HelloWorld != NULL)
HelloWorld ();
FreeLibrary(hInstLibrary);
}
}
DllMain
The DllMain function is an optional entry point into a dynamic-link library (DLL). It is called by the system whenever a process or thread loads or unloads the DLL. It can be used to perform simple initialisation and cleanup tasks.
The syntax is
BOOL WINAPI DllMain(HINSTANCE hinstDLL,handleDWORD fdwReason,LPVOID lpReserved ) { switch( fdwReason ) { // triggered when a DLL is being loaded into case DLL_PROCESS_ATTACH: memory for each new process. Returns FALSE if DLL failed to load. break; // triggered when current process is creating a case DLL_THREAD_ATTACH: new thread break; // triggered when a thread exits cleanly case DLL_THREAD_DETACH: break; // triggered when DLL is being unloaded from case DLL_PROCESS_DETACH:memory break; } return TRUE; // Successful DLL_PROCESS_ATTACH. }
Return Value
Returns TRUE if it succeeds or FALSE if initialisation fails
For further detailed reading –
https://docs.microsoft.com/en-us/windows/win32/dlls/dllmain