Link executable to DLL

Link executable to DLL
Executables link to (or load) DLLs in one of two ways:

  • Implicit linking , in which the operating system loads the DLL at the same time as the executable file that uses it. The client executable calls the DLL’s exported functions in the same way as if the functions were statically linked and included in the executable. Implicit linking is sometimes called static loading or load-time dynamic linking.

  • Explicit linking , where the operating system loads the DLL on demand at runtime. Executable files that use a DLL through explicit linking must explicitly load and unload the DLL. It must also set the function pointers used to access each function it uses from the DLL. Unlike function calls in statically linked libraries or implicitly linked DLLs, client executables must call exported functions in explicitly linked DLLs through function pointers. Explicit linking is sometimes called dynamic loading or runtime dynamic linking.

Executable files can be linked to the same DLL using either linking method. Furthermore, these methods are not mutually exclusive; one executable can be implicitly linked to a DLL and another executable can be explicitly attached to it.
Determine which linking method to use
Whether to use implicit or explicit linking is an architectural decision that must be made for the application. Each method has its own pros and cons.
Implicit link
Implicit linking occurs when an application’s code calls an exported DLL function. DLL function calls generate external function references in the object code when the source code of the calling executable is compiled or assembled. To resolve this external reference, the application must link with the import library (.lib file) provided by the DLL creator.

The import library contains code used only to load the DLL and implement calls to functions in the DLL. Looking for an external function in an import library tells the linker that the function’s code is in a DLL. To resolve external references to a DLL, the linker simply adds information to the executable file telling the system where to look for the DLL code when the process starts.

When the system starts a program that contains a dynamic link reference, it uses information from the program’s executable file to find the required DLL. If the DLL is not found, the system terminates the process and displays a dialog box reporting the error. Otherwise, the system maps the DLL module into the process address space.

If any DLL’s initialization and termination code (such as DllMain) has an entry point function, the operating system will call that function. One argument passed to the entry point function specifies code that instructs the DLL to attach to the process. If the entry point function does not return TRUE, the system terminates the process and reports an error.

Finally, the system modifies the process’ executable code to provide the starting address of the DLL function.

Like the rest of the program code, the loader maps the DLL code into the process’s address space when the process starts. The operating system only loads it into memory when needed. Therefore, the PRELOAD and LOADONCALL code attributes used by .def files to control loading in previous versions of Windows no longer make sense.
Explicit linking
Most applications use implicit linking because it is the simplest linking method available. However, sometimes explicit linking is required. Here are some common reasons for using explicit links:

  • The application does not know the name of the DLL it loads until it runs. For example, an application might obtain the name and exported functions of a DLL from a configuration file at startup.

  • If the DLL is not found when a process starts using implicit linking, the operating system terminates the process. Processes using explicit linking do not terminate in this case and can attempt to recover from the error. For example, a process can notify the user of an error and let the user specify an alternative path to the DLL.

  • A process using implicit linking also terminates if the DllMain function of any DLL it is linked to fails. Processes using explicit linking do not terminate in this case.

  • Applications that are implicitly linked to many DLLs may be slower because Windows loads all DLLs when the application loads. To improve startup performance, an application can use implicit linking only for DLLs that are required immediately after loading. It can load other DLLs using explicit linking only when needed.

  • Explicit linking eliminates the need to use import libraries to link applications. If a change in the DLL causes the export ordinal to change, the application does not need to relink when calling GetProcAddress with the function name instead of the ordinal value. Applications using implicit linking must still relink to the changed import library.

Here are two risks with explicit linking to be aware of:

  • If the DLL has a DllMain entry point function, the operating system calls that function in the context of the thread that calls LoadLibrary. If the DLL is already attached to the process, the entry point function is not called because the previous call to LoadLibrary did not make a corresponding call to the FreeLibrary function. If the DLL uses the DllMain function to initialize each thread of the process, explicit linking may cause problems because any threads that already exist when LoadLibrary (or AfxLoadLibrary) is called will not be initialized.

  • If a DLL declares static scope data as __declspec(thread), this may cause a protection fault when linked explicitly. Whenever code references this data after loading the DLL by calling LoadLibrary, a protection fault results. (Static scope data contains global and local static items.) This is why you should avoid using thread-local storage when creating a DLL. If this is not possible, inform the DLL user of the potential pitfalls of dynamically loading the DLL. For more information, see Searching Thread-Local Storage in Dynamic Link Libraries (Windows SDK).

How to use implicit links
To use a DLL through implicit linking, the client executable must obtain the following files from the DLL’s provider:

  • One or more header files (.h files) that contain declarations of exported data, functions, and C++ classes in the DLL. Classes, functions, and data exported by a DLL must all be marked with __declspec(dllimport) in the header file. See dllexport, dllimport for details.

  • Import library to be linked into the executable. When building a DLL, the linker creates an import library. For more information, see Using LIB Files as Linker Input.

  • Actual DLL file.

To use data, functions, and classes from a DLL through implicit linking, any client source file must contain a header file that declares them. From a coding perspective, a call to an exported function is like any other function call.

To build a client executable, you must link with the DLL’s import library. If you use an external makefile or build system, specify the import library along with other object files or libraries to link with.

When the operating system loads the calling executable, it must be able to find the DLL file. This means that you must deploy the DLL or verify that the DLL exists when you install the application.

How to explicitly link to a DLL

To use a DLL through explicit linking, the application must make a function call at run time to explicitly load the DLL. To link explicitly to a DLL, an application must:

  • Call LoadLibraryEx or similar function to load the DLL and obtain the module handle.

  • Call GetProcAddress to obtain the function pointer for each exported function called by the application. Because the application calls DLL functions through pointers, the compiler does not generate external references, eliminating the need to link with import libraries. However, there must be a typedef or using statement that defines the call signature of the exported function being called.

  • When the DLL has been processed, FreeLibrary is called.

For example, this example function calls LoadLibrary to load a DLL named “MyDLL”, calls GetProcAddress to get a pointer to a function named “DLLFunc1”, calls the function and saves the result, and then calls FreeLibrary to unload the DLL.

#include "windows.h"

typedef HRESULT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT*);

HRESULT LoadAndCallSomeFunction(DWORD dwParam1, UINT * puParam2)
{
    HINSTANCE hDLL; // Handle to DLL
    LPFNDLLFUNC1 lpfnDllFunc1; // Function pointer
    HRESULT hrReturnVal;

    hDLL = LoadLibrary("MyDLL");
    if (NULL != hDLL)
    {
        lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, "DLLFunc1");
        if (NULL != lpfnDllFunc1)
        {
            // call the function
            hrReturnVal = lpfnDllFunc1(dwParam1, puParam2);
        }
        else
        {
            // report the error
            hrReturnVal = ERROR_DELAY_LOAD_FAILED;
        }
        FreeLibrary(hDLL);
    }
    else
    {
        hrReturnVal = ERROR_DELAY_LOAD_FAILED;
    }
    return hrReturnVal;
}

Unlike this example, in most cases LoadLibrary and FreeLibrary should be called only once in an application for a given DLL. This is especially true if you are calling multiple functions in the DLL, or calling DLL functions repeatedly.