Click here to Skip to main content
14,920,872 members
Articles / Programming Languages / VC++
Tip/Trick
Posted 16 Aug 2012

Stats

48.7K views
2.4K downloads
43 bookmarked

Designing the Interface of DLLs in C/C++ Projects

Rate me:
Please Sign up or sign in to vote.
5.00/5 (13 votes)
19 Feb 2016CPOL5 min read
An advice to make your DLL interface more attractive and easier-to-maintain even in cross-platform projects

Introduction

This tip assumes that you are familiar with DLL usage and related terms like static/dynamic linking. If you have no idea how to use DLLs, then read this tip after learning the DLL related basics here (cross-platform wikipedia page), here (windows) or here (unix: linux, bsd, osx, etc.).

My advice is to never use DLLs in your project if you don't have to because they are trouble. If you still have to fall back on putting some C/C++ code to DLLs (or you have to create a plug-in interface) and it's up to you to design the DLL interface (that is used only by your C/C++ code), then read along. There is a minimalistic zipped project file attached with a Visual C++ 2010 solution and a unix build script to demonstrate plugin (DLL / shared library) loading on Windows and unix (linux/bsd/osx) platforms.

How Should a DLL Interface Look Like In My Opinion

First, declare an interface (a class that has only pure virtual methods) in the public header file of your DLL. It's quite important to use only pure virtual methods! After this, put the only exported function to your DLL that returns a pointer to this interface. After this, in the private source files of your DLL, you can derive a class from this interface and implement its methods. Now the users of the DLL just call the interface getter method of the DLL and then continue using it in a nice C++ish way by calling the methods of the retrieved interface pointer.

Don't forget to read the attached example source code. It is very simple and short.

Why Is This Good?

  • It simply looks nicer.
  • As a result of the thin linking interface between your DLL and the module that uses it - just one exported DLL function - it's very easy to make this cross-platform because the ugly ifdefs and platform dependent code is minimal. The thin interface makes it easy to implement platform independent delay loading.
  • It's very easy to merge this DLL code into your application later as part of a refactorization if you decide to do so - it's a breeze.
  • Let's say you are writing a plug-in interface for your program - it's very easy to put internal plug-ins to your executable by implementing the DLL interface inside your program. It becomes very easy to switch between an built in functionality and one that is implemented in a DLL, for your executable both kinds are visible just as a simple interface pointer.

Versioning Plug-in DLLs (My Style)

There are a lot of ways to detect the version of plug-ins. For example, by coding the version into the versioninfo resource of the DLL, coding the version to the filename, getting the version by calling a version getter exported function of the DLL... I use a totally different approach that has several advantages over the previously listed methods.

Let's say I have a media player program and a codec plug-in for it with a specific interface. After some time, I release a new version of the media player that has a modified interface but I decide to release the plug-in for older versions of the media player as well. I do this by writing a single DLL that supports both the old and the new version of the plugin interface. The public interface header of my plug-in DLL will contain the declaration of both the old and the new version of the interface and it contains two exported functions: one of them returns the old, and the other returns the new interface pointer. The exported methods have different names of course: GetMediaPlayerInterface() and GetMediaPlayerInterface2(). The DLL implements both interfaces and inside it can use a lot of shared code between the two implementations and I have to maintain only one project for that.

I have a piece of code that can detect if a DLL exports some functions without actually loading the DLL. This piece of code is useful for many reasons: If you have to load a DLL to find out whether it is your plugin or not, then during your LoadLibrary() call the DllMain() of the library may be executed inside your process even if it is not your plugin. Another advantage is faster execution that may count a lot if your app has lots of plugins. Here is another tip that contains the code that detects whether a DLL exports your desired function(s) without loading it with LoadLibrary(): Checking for exported symbols/functions in a DLL without loading it.

Advices to Design the Interface of DLLs Written in C

I myself never use C in user applications and I'm generally against the use of C when development isn't very low/system-level and a reasonably good C++ compiler is available on the specified platform. If you have the sources of a DLL that is written in C, then you can do the following:

  1. If you want to keep the C interface, then do the following:
    • Declare a struct in the public header of your DLL. The members of this struct will be function pointers. This struct will be the equivalent of the C++ interface class.
    • Somewhere in your DLL, define a (static) instance of this struct and fill it with pointers to your function implementations.
    • Export a single function from the DLL that returns a const pointer to the previously defined (static) struct instance.
  2. Alternatively you can create a C++ "wrapper" interface from which you call the original C functions.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

xenotron
Software Developer (Senior)
United Kingdom United Kingdom
No Biography provided

Comments and Discussions

 
Questionabout ' Advices to Design the Interface of DLLs Written in C' , give some sample? Pin
Tao craig4-Dec-17 15:06
MemberTao craig4-Dec-17 15:06 
Questionthanks for your sharing, This is a nice tip Pin
Tao craig4-Dec-17 14:34
MemberTao craig4-Dec-17 14:34 
SuggestionMemory management Pin
imagiro21-Feb-16 20:24
Memberimagiro21-Feb-16 20:24 
First of all: Totally agree, that's clean design. But if I remember right (unfortunately I didn't do any C++ for quite a while now), lifetime management can be tricky in such a case.

General rule: Allocation and deallocation should happen in the same place (the DLL), because the DLL and the application may be linked against different runtimes (and by this memory management functions). So saying new Foo() in the DLL, returning the object, and then later delete foo in the application might result in pretty nasty memory problems.
GeneralRe: Memory management Pin
xenotron22-Feb-16 2:23
Memberxenotron22-Feb-16 2:23 
Questionre Pin
marczo1220-Feb-16 0:03
Membermarczo1220-Feb-16 0:03 
QuestionNice tip - some clarifications about the projects' names Pin
StavrosApostolou18-Feb-16 2:56
MemberStavrosApostolou18-Feb-16 2:56 
AnswerRe: Nice tip - some clarifications about the projects' names Pin
xenotron18-Feb-16 9:48
Memberxenotron18-Feb-16 9:48 
GeneralRe: Nice tip - some clarifications about the projects' names Pin
StavrosApostolou21-Feb-16 22:36
MemberStavrosApostolou21-Feb-16 22:36 
AnswerRe: Nice tip - some clarifications about the projects' names Pin
xenotron19-Feb-16 16:13
Memberxenotron19-Feb-16 16:13 

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

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