Click here to Skip to main content
11,706,979 members (53,609 online)
Click here to Skip to main content

Dll Tips

, 4 Oct 2000 225.4K 88
Rate this:
Please Sign up or sign in to vote.
Tips for writting Dynamic Link Libraries
<!-- 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

Share

About the Author

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

You may also be interested in...

Comments and Discussions

 
QuestionCall VC++ dll from Javascipts Pin
zaiyatul hijah13-Aug-07 23:31
memberzaiyatul hijah13-Aug-07 23:31 
Generalnice one Pin
f214-Jul-06 9:32
memberf214-Jul-06 9:32 
GeneralDiplaying dialog from a dll Pin
Anonymous19-Jan-04 23:54
sussAnonymous19-Jan-04 23:54 
Generalregd dll for winamp Pin
karteek2-Dec-03 1:07
memberkarteek2-Dec-03 1:07 
Generalregd dll for winamp Pin
karteek2-Dec-03 1:05
memberkarteek2-Dec-03 1:05 
QuestionLoad the correct dll ? Pin
Timbavati24-Sep-03 6:03
memberTimbavati24-Sep-03 6:03 
GeneralAbout Load dialog from a DLL Pin
William G.S.20-Sep-03 5:02
memberWilliam G.S.20-Sep-03 5:02 
GeneralExtension DLL - Explicit Linking problem Pin
Anonymous30-Jul-03 21:28
sussAnonymous30-Jul-03 21:28 
GeneralRe: Extension DLL - Explicit Linking problem Pin
xicoloko31-Jul-03 0:23
memberxicoloko31-Jul-03 0:23 
GeneralRe: Extension DLL - Explicit Linking problem Pin
Anonymous31-Jul-03 19:21
sussAnonymous31-Jul-03 19:21 
GeneralExtension DLL - Explicit Linking GetProcAddress returns NULL Pin
rabbitkn10-Mar-04 20:18
memberrabbitkn10-Mar-04 20:18 
Generalinterfacing a dll with multithreaded application Pin
nishi_prasu26-Mar-03 23:14
membernishi_prasu26-Mar-03 23:14 
GeneralDLL X-Files Pin
Gregsan10-Aug-02 23:42
sussGregsan10-Aug-02 23:42 
GeneralDLLS creation Pin
Anonymous24-Mar-02 1:43
memberAnonymous24-Mar-02 1:43 
Generalrun a DLL from another EXE Pin
Impact23-Jan-02 4:10
memberImpact23-Jan-02 4:10 
GeneralRe: run a DLL from another EXE Pin
xicoloko23-Jan-02 4:32
memberxicoloko23-Jan-02 4:32 
GeneralRe: run a DLL from another EXE Pin
Impact23-Jan-02 14:10
memberImpact23-Jan-02 14:10 
GeneralRe: run a DLL from another EXE Pin
xicoloko24-Jan-02 4:34
memberxicoloko24-Jan-02 4:34 
GeneralRe: run a DLL from another EXE Pin
Impact28-Jan-02 14:07
memberImpact28-Jan-02 14:07 
GeneralRe: run a DLL from another EXE Pin
Carlos Antollini23-Jan-02 4:40
memberCarlos Antollini23-Jan-02 4:40 
GeneralAdding a dialog into dll, classwizard doesn't add *** line Pin
syd1-Jan-02 3:57
membersyd1-Jan-02 3:57 
GeneralRe: Adding a dialog into dll, classwizard doesn't add *** line Pin
Atul G. Katti8-Apr-02 19:20
memberAtul G. Katti8-Apr-02 19:20 
GeneralRe: Adding a dialog into dll, classwizard doesn't add *** line Pin
Rick Crone27-Jun-02 3:48
memberRick Crone27-Jun-02 3:48 
GeneralRe: Adding a dialog into dll, classwizard doesn't add *** line Pin
Atul G. Katti2-Jul-02 19:26
memberAtul G. Katti2-Jul-02 19:26 
GeneralRe: Adding a dialog into dll, classwizard doesn't add *** line Pin
Rick Crone3-Jul-02 3:01
memberRick Crone3-Jul-02 3:01 
QuestionHow I can will know function parameters? Pin
Nik Serdiuk17-Nov-01 9:28
memberNik Serdiuk17-Nov-01 9:28 
Questionhow to use dll without templet library file? Pin
ashutosh4-Nov-01 22:59
memberashutosh4-Nov-01 22:59 
AnswerRe: how to use dll without templet library file? Pin
ISandy16-Sep-03 19:53
memberISandy16-Sep-03 19:53 
GeneralExporting MFC classes to other languages Pin
Juan Herrera27-Aug-01 13:59
memberJuan Herrera27-Aug-01 13:59 
GeneralDifference Debug - Release Pin
Rene25-Jul-01 15:16
memberRene25-Jul-01 15:16 
GeneralRe: Difference Debug - Release Pin
djcat19-Sep-02 4:01
memberdjcat19-Sep-02 4:01 
GeneralWriting dll's Pin
Anonymous21-Jul-01 0:57
memberAnonymous21-Jul-01 0:57 
Generalseting file atributes in normal(not MFC) DLL Pin
MIlan Chudik22-Mar-01 3:46
memberMIlan Chudik22-Mar-01 3:46 
GeneralAnother tip for evolving data structs Pin
Wes Jones17-Jan-01 18:37
memberWes Jones17-Jan-01 18:37 
GeneralDetermining if class methods exist in exported object Pin
PeterK10-Oct-00 10:42
sussPeterK10-Oct-00 10:42 
QuestionAnd the allocation in DLL and deleting in main rpgram does not f*** up the heap? Pin
Mikko Mononen27-Jun-00 2:38
sussMikko Mononen27-Jun-00 2:38 
AnswerRe: And the allocation in DLL and deleting in main rpgram does not f*** up the heap? Pin
xicoloko27-Jun-00 3:49
sussxicoloko27-Jun-00 3:49 
GeneralRe: And the allocation in DLL and deleting in main rpgram does not f*** up the heap? Pin
GBO27-Jun-00 6:02
sussGBO27-Jun-00 6:02 
GeneralRe: And the allocation in DLL and deleting in main rpgram does not f*** up the heap? Pin
Stephen Kellett3-Jul-00 6:32
sussStephen Kellett3-Jul-00 6:32 
GeneralRe: And the allocation in DLL and deleting in main rpgram does not f*** up the heap? Pin
Karsten Blees22-Aug-00 14:53
sussKarsten Blees22-Aug-00 14:53 
GeneralVery good advice - but be aware of extension DLLs Pin
Andy Metcalfe9-Oct-00 22:08
sussAndy Metcalfe9-Oct-00 22:08 
GeneralRe: And the allocation in DLL and deleting in main program does not f*** up the heap? Pin
Arnt Witteveen8-Mar-01 3:45
memberArnt Witteveen8-Mar-01 3:45 
GeneralRe: And the allocation in DLL and deleting in main program does not f*** up the heap? Pin
Bernhard28-Apr-04 23:29
memberBernhard28-Apr-04 23:29 
GeneralRe: And the allocation in DLL and deleting in main program does not f*** up the heap? Pin
Arnt Witteveen28-Apr-04 23:47
memberArnt Witteveen28-Apr-04 23:47 
AnswerRe: And the allocation in DLL and deleting in main rpgram does not f*** up the heap? Pin
dumbo2-Jul-00 7:42
sussdumbo2-Jul-00 7:42 

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 | Terms of Use | Mobile
Web03 | 2.8.150819.1 | Last Updated 5 Oct 2000
Article Copyright 2000 by xicoloko
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid