Dynamic DLL Loading

When linking your application to a regular DLL, you can do it with either static linking or dynamic linking. Static linking is easier but if a DLL does not exist, your application cannot be started. Dynamic linking is a little bit harder but offers much more flexibility. If a DLL is not found, you can show a dialog box to inform a user and disable some features in your application that use a missing DLL. Missing DLL does not prevent your application to run normally.

This class offers a very easy way to dynamically load a DLL and use it afterwards. The class as it is should not be instantiated. You should derive a class of your own.

Step 1:

Class TBaseModule is a base class for all derived classes. Each derived class corresponds to one DLL.

#define BM_OK                   0
#define BM_DLLNOTFOUND          1
#define BM_INVALIDEXPORT        2
class TBaseModule {
    protected:
        int ErrorCode;        // One of BM_xxx defines
        int FunctionErrorCode;
        CString DLLName;
        HINSTANCE DLLHandle;
    public:
        TBaseModule(CString name);
        virtual ~TBaseModule();
        virtual BOOL Create(void);
        virtual void Destroy(void);
        int GetErrorCode(void)                  { return ErrorCode; }
        int GetFunctionErrorCode(void)          { return FunctionErrorCode; }
        CString& GetDLLName(void)               { return DLLName; }
};
Step 2:

Following is an implementation of this class:

TBaseModule::TBaseModule(CString name)
{
    DLLName = name;
    DLLHandle = NULL;
    ErrorCode = BM_OK;
    FunctionErrorCode = BM_OK;
}
TBaseModule::~TBaseModule()
{
    Destroy();
}
BOOL TBaseModule::Create(void)
{
    DLLHandle = ::LoadLibrary(DLLName);
    if (DLLHandle == NULL) {
        ErrorCode = BM_DLLNOTFOUND;
        return FALSE;
    }
    return TRUE;
}
void TBaseModule::Destroy(void)
{
    if (DLLHandle) {
        ::FreeLibrary(DLLHandle);
        DLLHandle = NULL;
    }
}
Step 3:

Now, let's assume that you want to dynamically load a DLL which exports the following functions and has a name "TEST.DLL" (DLL has a standard calling convention):

void ExportedFunction1(int code, const char *str);
WORD ExportedFunction2(DWORD *data);
char *ExportedFunction3(int code);
Step 4:

You have to define a type for each exported function and then derive a class TTestModule from base class TBaseModule.
 

typedef void (__stdcall *FExportedFunction1)(int code, const char *str);
typedef WORD (__stdcall *FExportedFunction2)(DWORD data);
typedef char * (__stdcall FExportedFunction3)(int code);
class TTestModule : public TBaseModule {
private:
    FExportedFunction1 FunctionExportedFunction1;
    FExportedFunction2 FunctionExportedFunction2;
    FExportedFunction3 FunctionExportedFunction3;
public:
    TTestModule(CString dllname);
    virtual BOOL Create(void);
    virtual void Destroy(void);
    void Function1(int code, const char *str);
    WORD Function2(DWORD data);
    char *Function3(int code);
};
Step 5:

Implementation of this derived class is the following:
 

TTestModule::TTestModule(CString dllname)
            :TBaseModule(dllname)
{
    FunctionExportedFunction1 = NULL;
    FunctionExportedFunction2 = NULL;
    FunctionExportedFunction3 = NULL;
}
BOOL TTestModule::Create(void)
{
    if (TBaseModule::Create()) {
        FunctionExportedFunction1 = (FExportedFunction1)::GetProcAddress(DLLHandle,_T"ExportedFunction1");
        FunctionExportedFunction2 = (FExportedFunction2)::GetProcAddress(DLLHandle,_T"ExportedFunction2");
        FunctionExportedFunction3 = (FExportedFunction3)::GetProcAddress(DLLHandle,_T"ExportedFunction3");
        if (FunctionExportedFunction1 && FunctionExportedFunction2 && FunctionExportedFunction3)
            return TRUE;
        ErrorCode = BM_INVALID_EXPORT;
        return FALSE;
    }
    return FALSE;
}
void TTestModule::Destroy(void)
{
    TBaseModule::Destroy();
    FunctionExportedFunction1 = NULL;
    FunctionExportedFunction2 = NULL;
    FunctionExportedFunction3 = NULL;
}
void TTestModule::Function1(int code, const char *str)
{
    if (DLLHandle == NULL)
        TRACE0(_T("TEST.DLL is not loaded - Use Create()\n"));
    FunctionErrorCode = BM_OK;
    if (FunctionExportedFunction1)
        FunctionExportedFunction1(code,str);
    else
        FunctionErrorCode = BM_INVALIDEXPORT;
}
WORD TTestModule::Function2(DWORD data)
{
    if (DLLHandle == NULL)
        TRACE0(_T("TEST.DLL is not loaded - Use Create()\n"));
    FunctionErrorCode = BM_OK;
    if (FunctionExportedFunction2)
        return FunctionExportedFunction1(data);
    FunctionErrorCode = BM_INVALIDEXPORT;
    return 0;
}
char *TTestModule::Function3(int code)
{
    if (DLLHandle == NULL)
        TRACE0(_T("TEST.DLL is not loaded - Use Create()\n"));
    FunctionErrorCode = BM_OK;
    if (FunctionExportedFunction3)
        return FunctionExportedFunction3(code);
    FunctionErrorCode = BM_INVALIDEXPORT;
    return NULL;
}
Step 6:

All you have to do to use this class is to declare it (yu can do it in several different ways: (1) as a data member of your CWinApp derived class, (2) as a local object within a function, (3) as a global object and (4) as a data member of any class). You have to call Create() and check return code. If it is FALSE, you can check error code and decide to abandon using DLL (since it is not loaded) or use it (since some functions are not loaded because they do not exist within a DLL).
 

TTestModule testDll(_T("TEST.DLL"));
....
BOOL retcode = testDll.Create();
if (retcode == FALSE) {
    if (testDll.GetErrorCode() == BM_INVALIDEXPORT)
        ::AfxMessageBox(_T("TEST.DLL does not contain all functions"));
    else if (testDll.GetErrorCode() == BM_DLLNOTFOUND)
        ::AfxMessageBox(_T("TEST.DLL is not found"));
}
....
testDll.Function1(0,NULL);
if (testDll.GetFunctionErrorCode() == BM_INVALIDEXPORT)
    ::AfxMessageBox(_T("ExportedFunction1 does not exist in a TEST.DLL"));
....
Use this class for your own DLLs or for system DLLs which are not part of the operating system.

That's all there is to it!
 

Last updated: 17 May 1998.



Comments

  • Easier binding with a factory object with virtual member functions

    Posted by Legacy on 03/04/1999 12:00am

    Originally posted by: Ernst Versteeg

    If you have a lot of functions you need for each function a
    GetProcAddress. In this case it is easier to import with GetProcAddress
    only one function which returns an object with virtual member
    functions.

    If the dll is build with the same development system as the application
    you can use the virtual member functions of this returned object
    without prior binding with GetProcAddress.

    The base class of the returned object is abstract and serves as
    protocoll which describes which functions should be implemented
    by the dll.

    So the dll exports only a create function which returns an object
    derived from the abstract base class.

    Reply
  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Protecting business operations means shifting the priorities around availability from disaster recovery to business continuity. Enterprises are shifting their focus from recovery from a disaster to preventing the disaster in the first place. With this change in mindset, disaster recovery is no longer the first line of defense; the organizations with a smarter business continuity practice are less impacted when disasters strike. This SmartSelect will provide insight to help guide your enterprise toward better …

  • Live Event Date: August 20, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT When you look at natural user interfaces as a developer, it isn't just fun and games. There are some very serious, real-world usage models of how things can help make the world a better place – things like Intel® RealSense™ technology. Check out this upcoming eSeminar and join the panel of experts, both from inside and outside of Intel, as they discuss how natural user interfaces will likely be getting adopted in a wide variety …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds