A DLL is Microsoft’s way of implementing a code library that can be used by more than one program at the same time. Unlike executable programs, DLL files can’t be run directly but instead 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 –
Any function within a DLL that will be called outside the DLL must be exported. Any DLL function that is 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()
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 will need to be in a directory where if can be found by the application. Windows will first search in the current application directory, the current working directory, the standard dll directory, and finally directories specified in the path variable.
//file name exampleDLL.lib
#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
There are two ways to load a DLL: implicit linking and explicit linking
Implicit linking is when the operating system loads the DLL at the same time as the executable file. The client program then calls the exported functions in the DLL the same way it would for those contained 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 exe file which imports and calls a simple dll function from the code above which display the messagebox.
//example console exe
#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 explicitly load and unload the DLL. Access to the DLL function is via a pointer.
The following example illustrates a simple exe file which imports and calls a simple dll function, from the dll file exampleDLL.dll (above)
#include <windows.h>
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);
}
}
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 initialization 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.
}
Returns TRUE if it succeeds or FALSE if initialisation fails
For further detailed reading –https://docs.microsoft.com/en-us/windows/win32/dlls/dllmain