Your browser doesn't support JavaScript DLLs - Windows Programming

DLLs

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.

//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

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.

//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 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)

#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);
}
}

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,    // handle to DLL module
DWORD fdwReason,       // reason for calling function
LPVOID lpReserved )    // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Occurs when a DLL is being loaded into memory for each new process. Return FALSE if DLL failed to load.
break;
case DLL_THREAD_ATTACH:
// occurs when current process is creating a new thread
break;
case DLL_THREAD_DETACH:
// occurs when a thread is exits cleanly
break;
case DLL_PROCESS_DETACH:
// Occurs DLL is being unloaded from 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