C/C++工程DLL中接口的设计

时间:2022-05-09 17:55:44

From:
http://www.codeproject.com/Tips/441838/Designing-the-Interface-of-DLLs-in-C-Cplusplus-P

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:

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.
Alternatively you can create a C++ “wrapper” interface from which you call the original C functions.

=========================================================
我的建议:
1 除法不得不,否则尽量不要使用DLL

2 DLL中类的成员函数最好声明为pure virtual methods