From ThirdMartini

Contents

[edit] Introduction

Dynamic DLL/Shared library binding allows an application to load a DLL/.so and use it's functionality without knowing about the libraries existance before hand. Statically bound DLLs can be used by an application by including the DLL's import library and header files when compiling the application. In the case of a Dynamic link the calling application only needs to know what function names to expect inside the DLL. An application that will be using a Dynamically Bound DLL must have place holders for the functions it will be using from the DLL.

Common uses of this style DLL binding are for Application Plugins where a 3rd party can develop a plugin for an application that they do not have the original source code for. Another common use is for Drivers where the driver can be added seperate of the application itself. In the Plugins case, on application start it can go off and scan a specific directory for DLL/.so files that can be used as plugins and loads them dynamically. The major benefit of this is that the DLLs can be added on the fly without having to release a new version of the Application that was compiled with the import libraries for that plugin.

[edit] Examples

[edit] Windows

This sample was tested using Borland C++ Builder 3.0 but it should work with other Windows compilers.

extern "C" __declspec(dllexport) WORD getModuleType();
extern "C" __declspec(dllexport) WORD getPluginType();
extern "C" __declspec(dllexport) WORD getDriverType();
extern "C" __declspec(dllexport) WORD getVersionMajor();
extern "C" __declspec(dllexport) WORD getVersionMinor();
extern "C" __declspec(dllexport) WORD openModule();
extern "C" __declspec(dllexport) WORD closeModule();
extern "C" __declspec(dllexport) WORD getModuleDescription(char *pDesc);
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
    return 1;
}
//---------------------------------------------------------------------------
// STANDARD DLL HEADER SET
WORD getModuleType()
{
    return MODULE_DRIVER;
}

WORD getDriverType()
{
    return DRV_PCT;
}

WORD getPluginType()
{
    return DRV_PCT;
}

WORD getVersionMajor()
{
    return 1;
}

WORD getVersionMinor()
{
    return 0;
}

WORD getModuleDescription(char *pDesc)
{
    strcpy(pDesc,"NULL Driver");
    return 0;
}

Sample Application Using The Above DLL

HINSTANCE hiDLL;
FARPROC  dll_getModuleDescription;
FARPROC  dll_getModuleType;
FARPROC  dll_getPluginType;
FARPROC  dll_getDriverType;
FARPROC  dll_getVersionMajor;
FARPROC  dll_getVersionMinor;  
void GetModuleDescription(char *pDLLName,char pDescription)
{
    hiDLL=LoadLibrary(pDLLName);
    dll_getModuleDescription    = getProcAddress(hiDLL,(LPCSTR)"_getModuleDescription");
    dll_getModuleType           = GetProcAddress(hiDLL,(LPCSTR)"_getModuleType");
    dll_getPluginType           = GetProcAddress(hiDLL,(LPCSTR)"_getPluginType");
    dll_getDriverType           = GetProcAddress(hiDLL,(LPCSTR)"_getDriverType");
    dll_getVersionMajor         = GetProcAddress(hiDLL,(LPCSTR)"_getVersionMajor");
    dll_getVersionMinor         = GetProcAddress(hiDLL,(LPCSTR)"_getVersionMinor");
     
    typedef WORD (__cdecl *IMPPROC) (char *);
    if(dll_getDriverDescription!=NULL)
    {
        ((IMPPROC) dll_getModuleDescription)(pDesc);
        return true;
    }
    else
    {
        strcpy(pDesc,"");
        return false;
    } 
}

[edit] Explanation:

[edit] hiDll=LoadLibrary(dll_name)

The LoadLibrary function is a call to the Win32 API that will load a DLL into memory and returns the DLL's Instance to the caller. hiDll will be set to a non-0 number if the DLL was found.

[edit] dll_getModuleDescription = GetProcAddress(hiDLL,(LPCSTR)"_getModuleDescription")

GetProcAddress will go off into the DLL instance previously loaded with LoadLibrary and find the specified function then return a pointer to it's code segment. We assign this pointer to our place holder function dll_getModuleDescription

[edit] typedef WORD (__cdecl *IMPPROC) (char *)

Since the getModuleDescription function residing in the DLL takes a single parameter and is declared as an "C" style prototype we use this typedef to cast our function as dll_getModuleDescription(char *)

[edit] ((IMPPROC) dll_getModuleDescription)(pDesc)

Finally we call the getModuleDescription function inside our DLL.

[edit] Gotchas:

When writing code that loads DLL dynamically in this manner it is important to match the way the function was prototyped inside the DLL with the way it is prototyped inside the application. For instance if inside our application we prototyped the dll_getModuleDescription function as:
typedef WORD (__stdcall *IMPPROC) (char *) 
Notice that it's now __stdcall instead of __cdecl the application will crash upon the exit of the function because of stack corruption. (The char * parameter is passed diferently depending on the decleration type)
Personal tools