I'm having a huge problem trying to learn how to export classes from a DLL.

I can do some functions just fine but the classes are mangled :S

I've tried from .def file, I've used extern "C" but when I did, it threw errors and won't export the class at all.

In codeblocks it won't create a .lib file so I tried linking the .a file but that still doesn't work. I'm not sure what to do. I'd probably prefer either loadlibrary or .lib but I want to learn how to do it via a .def file.



#define EXPORT __declspec(dllexport)

class EXPORT Point;   //Forward declaration of a class I want to export. This is all I did.




#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
#include "Strings.hpp"
#include <Time.h>
#include <vector>
#include "Exports.hpp"

EXPORT DWORD SystemTime();

EXPORT DWORD GetTimeRunning();

EXPORT DWORD TimeFromMark(int TimeMarker);

EXPORT std::string TheTime();

EXPORT int AddOnTermination(void(*function)(void));

EXPORT std::string GetEnvironmentVariables(const std::string Variable);

EXPORT void SetTransparency(HWND hwnd, BYTE Transperancy = 0);


Then in the CPP file I just have the definitions of each of those functions. They don't have the EXPORT infront of them.

For classes I just forward declare them in the Exports header and put export betwee class and the classname.

My Main file looks like:

#include "System.hpp"   //File that includes the exports.

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    switch (fdwReason)
        case DLL_PROCESS_ATTACH:
            // attach to process
            // return FALSE to fail DLL load

        case DLL_PROCESS_DETACH:
            // detach from process

        case DLL_THREAD_ATTACH:
            // attach to thread

        case DLL_THREAD_DETACH:
            // detach from thread
    return TRUE; // succesful

I have around 200 classes to export and about 300 functions. I don't mind exporting the functions one by one or using a def file with ordinal exportation but I have no clue how to do the classes.

Any idea? How do I write the typedef for a class? Am I exporting them right?

I've run across this before, and the short answer is: you can't.

DLLs were designed originally with the Pascal language in mind, and as a result, older 16-bit DLLs often used the Pascal parameter passing conventions. By the time Win32 came on the scene, Pascal was largely forgotten, but, Visual Basic was on the rise inside of Microsoft, so a new calling convention, __stdcall, was developed for language-indpendent parameter passing. This became the standard for pretty much all modern DLLs.

One thing that was not supported was classes. Object models of different languages were too different, and for system programming Microsoft assumed you'd be using C in any case. Full support for object-oriented programming didn't come around until .NET, and then only for .NET style objects and classes.

The practical upshot of this is that while you can have a class inside of a DLL, you have to 'unwrap' the class by providing external functions which act as an intermediary to the class's methods.

commented: Indeed. +5

Full support for object-oriented programming didn't come around until .NET, and then only for .NET style objects and classes.

Well, that's not true at all. On the Windows side, there were many frameworks before .NET which could and still can export classes. In particular, COM objects (and their derivatives, like OCX and ActiveX). I have personally never worked with that, but apparently, it is not too hard, and doesn't require too much additional code to wrap the classes you wish to export.

Then, in theory, classes are exportable in C++ (with a simple __declspec(dllexport) statement in the declaration). However, due to the lack of a strict binary-compatibility specification for object layouts in C++, and due to the lack of standard name-mangling rules, it basically boils down to the fact that you cannot export classes from a DLL unless the DLL and the executable (or whatever else is linking to the DLL) were compiled with the exact same compiler (and version), on the exact same platform and with all the exact same compiler options, at least, if using MSVC. The C++ compiler in GCC gave itself very strict name-mangling rules and a standard binary-compatibility interface that it has stuck to for some time. This means that exporting / importing classes from libraries using GCC is much more portable (e.g., different versions of GCC and different compilation options). This is why many libraries in the GNU/Linux world do export classes directly (in fact, by default).

However, to be safe, in most cases, you should just avoid exporting classes (especially under Windows). The general way to do it is to wrap class member function calls into C-style functions that take an opaque pointer as the first parameter:


#ifndef MY_DEFINES_H
#define MY_DEFINES_H

#define DLL_FUNCTION extern "C" __declspec(dllimport) 
#define DLL_FUNCTION extern "C" __declspec(dllexport)

#define DLL_CALL __stdcall



#ifndef MY_CLASS_H
#define MY_CLASS_H


typedef void* MyClassPtr;


class MyClass {
    void say_hi() const;

typedef MyClass* MyClassPtr;


DLL_FUNCTION MyClassPtr DLL_CALL MyClass_create();
DLL_FUNCTION void DLL_CALL MyClass_free(MyClassPtr p_obj);

DLL_FUNCTION void DLL_CALL MyClass_say_hi(MyClassPtr p_obj);


// my_class.cpp:

#include "my_class.h"
#include <iostream>

void MyClass::say_hi() const {
  std::cout << "Hello World!" << std::endl;

DLL_FUNCTION MyClassPtr DLL_CALL MyClass_create() {
  try {
    return new MyClass();
  } catch(...) {
    return NULL;

DLL_FUNCTION void DLL_CALL MyClass_free(MyClassPtr p_obj) {
  try {
    delete p_obj;
  } catch(...) { };

DLL_FUNCTION void DLL_CALL MyClass_say_hi(MyClassPtr p_obj) {
  try {
  } catch(...) { };    // NOTE: You must use a catch-all statment like this one.

The reason for those catch-all statement is to make sure that C++ exceptions are not allowed to propagate outside the DLL function. There are also ways to translate an exception to something more DLL friendly (like in Win32 API with their error-codes and the function to get the last error message, they basically catch the exception, store the message within the DLL and output an error-code which can be used to retrieve the message with another DLL fucntion call).

It is also possible to re-wrap all the DLL function calls within a class, so that it becomes transparent to the user (e.g., the user is still just using a class, but doesn't see the underlying calls to DLL functions). I mean, you can do something like this:

class MyImportedClass {
    MyClassPtr p_obj;
    MyImportedClass() : p_obj(MyClass_create()) { };
    ~MyImportedClass() { MyClass_free(p_obj); };

    void say_hi() const { MyClass_say_hi(p_obj); };

Then, the user can use it as if it was the original class (within the DLL), you can also figure out a way to use the name "MyClass" for the imported wrapper class too, this way, the user code is identical to the original.

However, doing all of the above for all your classes can be a real pain in the neck. So, first of all, you must think carefully about what you want to export and what you don't need to export, to reduce your library's interface to a minimum. Also, you should consider creating a somewhat standard way to do the above such that you can generate all the code (very repetitive code) automatically (something like a set of MACROs or using some template-magic, if you can).

Another solution that I like particularly is to use Python bindings. The Boost.Python library provides an extremely nice way to very easily export your C++ classes as Python classes (under-the-hood, it probably produces something very similar to what I wrote above, but automatically). Then, you can use Python for all the high-level work, like creating and assembling the objects together and calling high-level functions on them. I'm in the process of doing this in my own library, and it's really easy. This is a very nice solution when creating library components in C++ and wanting to use them in a plug-and-play fashion at a higher-level (and Python is great for that, but I don't know how well it works in Windows).

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.