Click here to Skip to main content
Click here to Skip to main content

Dll Tips

By , 4 Oct 2000
Rate this:
Please Sign up or sign in to vote.
<!-- Add the rest of your HTML here -->

Dynamic Link Libraries using with MFC

This document is intended to give a beginner knowledge that may be helpful when designing a project for the Windows platform. When I start a new project I try to put all code that has the greatest chance of changing into a DLL. This provides the ability to make updates to the project without having to recompile every piece. This allows for a minimum piece of code to be redistributed.

For this to work properly, there are some tips that must be followed. Much of you are asking “Why this @$&^# doesn’t use COM ?”. Of course COM is a good choice, but I’m here to show another way. Some of this code looks like COM (of course I use it’s architecture!!).

The problem with DLL’s (specially those that use MFC) is that the debug and release versions are incompatible. You have probably seen this when running a debug application version with the DLL release version. The whole world gets crazy!! The best way, in fact the way Microsoft does it, is to give different names to the different builds of the DLL. The release build of the DLL uses the [Project Name].DLL format while the debug version will use the [Project Name]D.DLL format. Note the "D" after the project name. Using this approach allows you to send the two DLLs to the installation directory with an application build and the application will work properly.

Example: Naming convention for different builds of the same DLL

These are the steps needed to achieve this (Assume the project name is AAA):

  1. Copy the AAA.def to AAAD.def and change all the AAA occurrences to AAAD.
  2. In the Project/Settings dialog, select Win32 Debug Build.
  3. Under the tab Link change the Output file name to AAAD.DLL.
  4. At the bottom of the property page you will see something like:
    /def:".\AAA.def" /out:"Debug/AAAD.DLL"
    Change to:
    /def:".\AAAD.def" /out:"Debug/AAAD.DLL"
  5. Now the debug version will create AAAD.lib and AAAD.DLL files.

When I create a DLL, I create an include header for it (I think everybody does), which I named DLL header. This header has all the exported class definitions. And to be more efficient I include the linking stuff in this file also. I would do this so you do not have to add the lib file to the Project Settings. My header looks like:

#ifndef DEF_MUDASDASDASDASDAS
#define DEF_MUDASDASDASDASDAS

#ifdef _DEBUG
#pragma comment(lib, AAAD.lib)
#else
#pragma comment(lib, AAA.lib)
#endif

... the class definitions go here

#endif //MUDASDASDASDASDAS


PROGRAMMING FOR CHANGES

The preferred kind of DLL used to export classes is a MFC extension DLL. By using this you can easily instantiate a class that is within a DLL. To do this you just declare the class as follows:

class AFX_EXT_CLASS CFoo
{
     ...

}

Evolving Implementations

In the application that uses this class you need to include the DLL header and everything is cool. The problem is: every time you need to include a member variable or a method to an exported class you have to change the DLL header. This means that every component that uses the dll must be recompiled. For new methods I don’t know a way to overcome this recompilation problem, but for new variables there’s a workaround.

Example: Handling Evolving Data Member Implmentation

Instead of declaring the member variables directly in the class body, you create a kind of implementation class, like the sample code:

class CFooImpl;
class CFoo
{
     ...

protected:
     CFooImpl* m_pThis;

};

The CFooImpl class doesn’t need to be exposed to the components that use the DLL. The implementation of CFooImpl would look like:

class CFooImpl
{
public:
    CString m_sName;
};

 

CFoo::CFoo()
{
    m_pThis = new CFooImpl;
    m_pThis->m_sName = _T(&#8220;Unknown&#8221;);
}


CFoo::~CFoo()
{
    delete m_pThis;
}

Evolving Data Structures

Another way to prepare for changes is to use intelligent structs the way that the Windows API does. You declare a method that has an LPVOID as in and out parameter. These pointers are address of struct instances. The trick is to define the first struct a member of DWORD type to hold it’s size. This way you can determine which data is available in the struct.

Example: Evolving Data Structures

 
typedef struct tagCHANGEABLE
{
     DWORD dwSize;
     long lBytes;
}CHANGEABLE, *LPCHANGEABLE;


BOOL CFoo::Method(LPVOID lpIn)
{
     LPCHANGEABLE lpChangeable = (LPCHANGEABLE)lpIn;

     if (lpChangeable->dwSize == sizeof(CHANGEABLE))
     {
         ...
         return TRUE;
     }
 
     return FALSE;
}

Using it:

CFoo myFoo;

CHANGEABLE changeable;
memset(&changeable, 0, sizeof(changeable));

changeable.dwSize = sizeof(changeable);

myFoo.Method(&changeable);



DLL LOADED WHEN NEEDED

Sometimes you have situations that requires you to call a dialog or create a class instance. So you decide to put those items in a DLL, but you don’t want the DLL to be loaded when the application gets executed. You want to load the DLL when needed (COM). This kind of DLL I call Dynamic DLL (stupid name I know “Dynamic Dynamic link libraries”).

Example: Loading A DLL As Needed

So you declare the exported function as:

__declspec( DLLexport )
void MyExportedFunc(DWORD dw)
{
     ...
}

We need to include this function in the def files (debug and release). The debug def file would look like this:

; AAAD.def : Declares the module parameters for the DLL.

LIBRARY      "AAAD"

DESCRIPTION  'AAAD Windows Dynamic Link Library'

EXPORTS
    MyExportedFunc @1
    ; Explicit exports can go here

Now to use this function we need to load the library, find the function entry point and call it.

typedef void (*MYFUNC)(DWORD);  

#ifdef _DEBUG
    HINSTANCE hDLL = AfxLoadLibrary("AAADLLD");
#else
    HINSTANCE hDLL = AfxLoadLibrary("AAADLL");
#endif

    if (hDLL)
    {
        FARPROC pnProc = GetProcAddress(hDLL, "MyExportedFunc");
        MYFUNC pnMyfunc = (MYFUNC)pnProc;

        pnMyfunc(0);

        FreeLibrary(hDLL);
     }

Remember that to show a dialog you must take care of the resource stuff (AfxSetResource..). You can also use this approach to create class instances. The class definition must use pure virtual functions (to avoid an unresolved external symbol). This is just like COM.
The class definition should look like this:

class CFoo
{
public:
   virtual void Initialize (CString sName) = 0;
};

You implement this “interface” with another class that is not visible through the DLL header file.

class CFooImp  : public CFoo
{
public:
    CFooImp();
    virtual ~CFooImp();

    void Initialize (CString sName)
    {
        m_sName  = sName;
    }

protected:
    CString m_sName;
};

To create an instance of this class (interface) you create an exported function.

__declspec(DLLexport)

CFoo* CreateFoo(DWORD dwVersion)
{
     if (dwVersion == CURRENT_VERSION)
        return new CFooImp;

     return NULL;
}

The application creates the class instance like this:

typedef CFoo* (*MYFUNC)(DWORD);  

#ifdef _DEBUG
    HINSTANCE hDLL = AfxLoadLibrary("AAADLLD");
#else
    HINSTANCE hDLL = AfxLoadLibrary("AAADLL");
#endif

    if (hDLL)
    {
        FARPROC pnProc = GetProcAddress(hDLL, " CreateFoo");
        MYFUNC pnMyfunc = (MYFUNC)pnProc;

        CFoo* pFoo = pnMyfunc(0);

        pFoo->Initialize(_T("Hi"));

        delete pFoo;
 
        FreeLibrary(hDLL);
    }

Remember that you cannot free the library that contains the CFoo implementation until you have deleted the CFoo instance.



CONCLUSION

These examples explain the powers of well-designed DLLs. A good design is the first and most important step to the successful project. Unfortunately, if the whole project has a poor design no miracle will make your applications easy to change and update.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

xicoloko
Architect VisionOne AG
Switzerland Switzerland
XicoLoko is a brazilian developer based in Switzerland.

Comments and Discussions

 
QuestionCall VC++ dll from Javascipts Pinmemberzaiyatul hijah13-Aug-07 23:31 
Generalnice one Pinmemberf214-Jul-06 9:32 
GeneralDiplaying dialog from a dll PinsussAnonymous19-Jan-04 23:54 
Generalregd dll for winamp Pinmemberkarteek2-Dec-03 1:07 
Generalregd dll for winamp Pinmemberkarteek2-Dec-03 1:05 
QuestionLoad the correct dll ? PinmemberTimbavati24-Sep-03 6:03 
GeneralAbout Load dialog from a DLL PinmemberWilliam G.S.20-Sep-03 5:02 
GeneralExtension DLL - Explicit Linking problem PinsussAnonymous30-Jul-03 21:28 
GeneralRe: Extension DLL - Explicit Linking problem Pinmemberxicoloko31-Jul-03 0:23 
GeneralRe: Extension DLL - Explicit Linking problem PinsussAnonymous31-Jul-03 19:21 
GeneralExtension DLL - Explicit Linking GetProcAddress returns NULL Pinmemberrabbitkn10-Mar-04 20:18 
Generalinterfacing a dll with multithreaded application Pinmembernishi_prasu26-Mar-03 23:14 
GeneralDLL X-Files PinsussGregsan10-Aug-02 23:42 
GeneralDLLS creation PinmemberAnonymous24-Mar-02 1:43 
Generalrun a DLL from another EXE PinmemberImpact23-Jan-02 4:10 
GeneralRe: run a DLL from another EXE Pinmemberxicoloko23-Jan-02 4:32 
GeneralRe: run a DLL from another EXE PinmemberImpact23-Jan-02 14:10 
GeneralRe: run a DLL from another EXE Pinmemberxicoloko24-Jan-02 4:34 
GeneralRe: run a DLL from another EXE PinmemberImpact28-Jan-02 14:07 
GeneralRe: run a DLL from another EXE PinmemberCarlos Antollini23-Jan-02 4:40 
GeneralAdding a dialog into dll, classwizard doesn't add *** line Pinmembersyd1-Jan-02 3:57 
GeneralRe: Adding a dialog into dll, classwizard doesn't add *** line PinmemberAtul G. Katti8-Apr-02 19:20 
GeneralRe: Adding a dialog into dll, classwizard doesn't add *** line PinmemberRick Crone27-Jun-02 3:48 
GeneralRe: Adding a dialog into dll, classwizard doesn't add *** line PinmemberAtul G. Katti2-Jul-02 19:26 
GeneralRe: Adding a dialog into dll, classwizard doesn't add *** line PinmemberRick Crone3-Jul-02 3:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140415.2 | Last Updated 5 Oct 2000
Article Copyright 2000 by xicoloko
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid