intelliproject logo

Location: Desktop development - C/C++    License: The Intelliproject Open License (IPOL)

How to export C++ classes and functions from a DLL

Posted by Silviu Caragea

This article describes different methods to export a C++ function or class from a DLL module. It presents the advantages of using DLLs, the types of DLLs and finally the advantage / disadvantages of using ATL interfaces to export objects from DLLs.

Skill: Advanced

Posted: 08/12/2008

Views: 1565

Rating: 5.00 /5

Popularity: 0.00

Sign Up to vote for this article

Introduction

Dynamic link library, or DLL, is Microsoft's implementation of the shared library concept in the Microsoft Windows and OS/2 operating systems. These libraries usually have the file extension DLL, OCX (for libraries containing ActiveX controls), or DRV (for legacy system drivers).

As executables files, DLLs can contain code, data, and resources, in any combination.

In a nut shell, a DLL is a library that contains code and data that can be used by more than one program at the same time.

By using a DLL, a program can be modularized into separate components. For example, there are a lot of programs which have plugins which contains different features. Each plugin can be loaded into the main program at run time if that module is installed.

Because the modules are separated, the load time of the program is faster, and a module is only loaded when that functionality is requested.

Additionally, updates are easier to apply to each module without affecting other parts of the application.

The advantages of DLLs

The following list describes some of the advantages of using DLL's in ours applications.

  • Uses a small number of resources - when multiple applications use the same pieces of code, a DLL can reduce the duplication of code that is loaded on the disk and in physical memory.
  • Promotes modular architecture - a DLL helps promote developing modular programs. This helps developer to build applications which can load their desired modules dynamically at run time.
  • Eases deployment and installation - when a function within a DLL needs to be updated or fixed, the deployment and installation of the DLL does not require the program to be relinked with the DLL. Additionally, if multiple programs use the same DLL, the multiple programs will all benefit from the update.

Types of DLLs

The DLLs can be linked in two ways in an application. These two methods of linking are "load-time dynamic linking" and "run-time dynamic linking".

Load-time dynamic linking

In load-time dynamic linking, an application makes explicit calls to exported DLL functions like local functions. To use load-time dynamic linking, provide a header (.h) file and an import library (.lib) file when you compile and link the application. When you do this, the linker will provide the system with the information that is required to load the DLL and resolve the exported DLL function locations at load time.

Run-time dynamic linking

In run-time dynamic linking, an application calls either the LoadLibrary function or the LoadLibraryEx function to load the DLL at run time. After the DLL is successfully loaded, you use the GetProcAddress function to obtain the address of the exported DLL function that you want to call.

When to use "Load-time linking" and when to use "Run-time linking"

The following list contains some advice on when to use load-time dynamic linking and when to use run-time dynamic linking:

  • Startup performance - If the initial startup performance of the application is important use run-time dynamic linking.
  • Ease of use - in load-time dynamic linking, the exported DLL functions are like local functions.This makes it easy for you to call these functions.
  • Application logic - In run-time dynamic linking, an application can load different modules as required. This is important when you develop modular applications.

Exporting DLL functions

To access the functions within the DLL, it is necessary to tell the compiler to export the desired symbols. First of all, you must remove the issue of C++ name decoration. MSVC compiles your source as C++ if it has a .cpp or .cxx extension. If the source file has a .c extension, then MSVC compiles it as C. If you compile your file as C++, then the function names are normally decorated in the output code. This might be problematic because the function name has extra characters added to it. To avoid this problem, declare the function as extern "C" in the function declaration, as follows:

extern "C" int __declspec(dllexport) nr_difference(int a , int b);

To use exported DLL functions in the application, you must declare each function that you want to import with the following keyword:__declspec(dllimport)

Link your exported functions using Load-time dynamic linking

To use the load-time dynamic linking you need the .lib (generated during the compile process) and the header which contain your exported functions prototype.

You must specified in you project settings the library which will be used to link your imported functions. Also you can do this in your source code using the following preprocessing directive:

#pragma comment (lib,"../the_dll/Debug/the_dll.lib")

Link your exported functions using Run-time dynamic linking

To use the run-time dynamic linking you must used 3 important functions:

  1. LoadLibrary or LoadLibraryEx- Loads the specified module into the address space of the calling process. The specified module may cause other modules to be loaded.
  2. GetProcAddress - Retrieves the address of an exported function or variable from the specified dynamic-link library (DLL).
  3. FreeLibrary - Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. When the reference count reaches zero, the module is unloaded from the address space of the calling process and the handle is no longer valid.

First of all you should create pointers to functions which will be used to retain the address returned by GetProcAddress.

Suppose my function looks like: int nr_difference(int a , int b);

A pointer to a function which return an int value and takes two int parameters will looks like:

typedef int (*differenceFunction)(int,int);//differenceFunction is the pointer name.

After that we must load the specified DLL into address space of the calling process.

After that we retain the address of the exported function from our DLL in the pointer declared above.

Now we can call our function like that: printf("A - B = %d \n" ,diffFunc(a,b));

Finally when you want to unload your DLL you must call FreeLibrary

Exporting classes from a DLL

Exporting a C++ class is similar to exporting C functions. All you must to do is to use the __declspec(dllexport/dllimport) directive before the class name if the whole class needs to be exported, or before the method declarations if only specific class methods need to be exported.

decorate.jpg

The above output was generated with Dependency Walker tool. As you can see the methods are decorated. So let's undecorated them ...

undecorate.jpg

Maybe you have already noticed that the Dependency Walker shows an additional exported member:

CArithmeticalOperations::operator=(class CArithmeticalOperations const &) 

Conceptually, every class object has four special member functions:

  1. default constructor
  2. copy constructor
  3. assignment operator
  4. destructor

If these members are not explicitly declared by the programmer, the implementation implicitly declares them and generates an implicit default implementation.

Using an Abstract ATL Interface to export your classes

A C++ abstract interface is just a class that contains only pure virtual methods and no data members.

All you must to do is to provide a header file with an interface declaration and implement a factory function that will return the new object instance. Only the factory function has to be declared with the __declspec(dllexport/dllimport) directive.

In the above example my interface is called IArithmeticalOperations . The factory function is called CreateIArithmeticalOp and it's used to create a new object instance.

The implementation is found in CArithmeticalOperationsImpl which is derived from IArithmeticalOperations.

The IUnknown interface lets clients get pointers to other interfaces on a given object through the QueryInterface method, and manage the existence of the object through the IUnknown::AddRef and IUnknown::Release methods. All other COM interfaces are inherited, directly or indirectly, from IUnknown. Therefore, the three methods in IUnknown are the first entries in the VTable for every interface.

The following example shows how to use your interface in the application:

First of all we retain the factory function address in a pointer. After that we must creating a new object instance and finally we can call the interface methods.

Why to use interfaces

  • Your exported class can be used via an interface with any C++ compiler
  • Because resource allocation and release happens entirely inside a DLL module, a client is not affected by a DLL's choice of CRT.
  • The resulting DLL module can be redesigned and rebuilt without affecting the rest of the project.

Disadvantages of interfaces

  • An explicit function call is required to create a new object instance and to delete it. A smart pointer can spare a developer of the latter call, though.
  • An abstract interface method cannot return or accept a regular C++ object as a parameter. It has be either a built-in type (like int, double, char*, etc.) or another abstract interface. It is the same limitation as for COM interfaces.

Summary

This article describes different methods to export a C++ function or class from a DLL module. It presents the advantages of using DLLs, the types of DLLs and finally the advantage / disadvantages of using ATL interfaces to export objects from DLLs.

License

This article, along with any associated source code and files, is licensed under The Intelliproject Open License (IPOL)

About the author

Silviu Caragea

Silviu Caragea is the Founder, Administrator and Chief Editor who wrote and runs The IntelliProject.

He's been programming since 2000 and now he's student at The Faculty of Economic Cybernetics, Statistics and Informatics from Bucharest. In the same time he's working as software developer at Cratima Software, a Romanian software and web design company that activates both on the local and foreign market, providing its customers with software development services, internet and intranet solutions, web design, graphic design and IT consultancy.

His programming experience includes:
- C,C++, Visual C++(Win32 API, MFC, ADO, STL, DAO, ODBC, ATL, COM, DirectShow, DirectDraw, WTL)
- Open Source libraries :CURL & Boost
- HTML, CSS
- Java (SE,ME)
- JavaScript, Ajax, Google Web Toolkit (GWT)
- Php, MySQL
-Oracle, PL SQL
- C# .NET
-Objective C, IPhone SDK, Cocoa

Location: Romania
Ocupation: Software Engineer
Home page: http://www.intelliproject.net

Sign up to post message on the article message board!