I can't figure out for the life of me how to import a class declared, defined and implemented within a dll into a host app using any GNU build systems. The two compiler suites I have are Dev C++ and the newer Code::Blocks.

I have no problem with this using any Microsoft products that I have. The two Microsoft products I have are Visual C++ 6 and eMbedded Visual C++ 4.0.

Below is a simple test dll & host app to show my difficulty, along with Compile Log tab and Compiler Tab from Dev C++ (The CodeBlocks errors are exactly the same). The dll - dllCBox - just creates and exports a simple class to calculate the volume of a box. The host app simply tries to import the class, declare a CBox, and output its volume. Note that this is just a test case I put together to concisely show the problem. In the real situation I create a String class of my own within a dll where I create several grid custom controls. In the host that creates instances of the custom controls I also have access to my string class. This architecture is something I use to good advantage frequently, rather than implementing the same string class in the dll & the host app, which would be wasteful. Anyway, here is the example...

//Project dllCBox;  File dllMain.cpp
#include <windows.h>
#include <stdio.h>

extern "C" class __declspec(dllexport) CBox
{
 public:
 CBox(double dblLen, double dblWidth, double dblHeight)
 {
  printf("Called CBox() Constructor\n");
  m_Length=dblLen;
  m_Width=dblWidth;
  m_Height=dblHeight;      
 }  
 
 ~CBox()
 {
  printf("Called CBox() Destructor\n");        
 }
 
 double Volume()
 {
  return m_Length*m_Width*m_Height;       
 }       
 
 private:
 double m_Length;
 double m_Width;
 double m_Height;                              
};


BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved)
{
 switch(reason)
 {
  case DLL_PROCESS_ATTACH:
    break;
  case DLL_PROCESS_DETACH:
    break;
 }

 return TRUE;
}

Here is a simple Host app that just uses the CBox class to get the
volume of a 3 by 4 by 5 box...

//Project CBoxHost;  File Main.cpp
#include <stdio.h>

extern "C" class __declspec(dllimport) CBox
{
 public:
 CBox(double,double,double);       
 ~CBox();
 double Volume();
 
 private:
 double m_Length;
 double m_Width;
 double m_Height;              
};                


int main(void)
{
 CBox box1(3.0,4.0,5.0);
 
 printf("box1.Volume()=%f\n",box1.Volume());
 getchar();
 
 return 0;   
}

Here is output from either VC++ 6 or Windows CE eMbedded VC++ 4.0 on Handheld. There it works like a charm. The
mechanism there is to tell the IDE that the host project is dependent on the dll project.

/*
//Output fro VC++ 6 or on handheld with eMbedded VC++ 4.0

Called CBox() Constructor
box1.Volume()=60.000000
Called CBox() Destructor
Press any key to continue
*/


With either of the GNU compiler suites (Dev C++ or CodeBlocks) there is an option to specify 'parameters' to the Host app build. With Dev C++ you go to the 'Project' menu and execute 'Project Options'. That brings up a dialog with tabs and if you choose the Linker tab you can add the proper export lib from the dll which you wish the host app to link against. libdllCBox.a is what is produced by Dev C++ & CodeBlocks using the GNU compilers. Below are the error messages from Dev C++. The ones from CodeBlocks are about the same....

Compile Log Tab
==============================================
Compiler: Default compiler
Building Makefile: "C:\Code\Dev-Cpp\Projects\dllCBox\Makefile.win"
Executing make...
make.exe -f "C:\Code\Dev-Cpp\Projects\dllCBox\Makefile.win" all

g++.exe -c Main.cpp -o Main.o
-I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include"
-I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32"
-I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include"

g++.exe Main.o -o "Boxes.exe" -L"C:/Dev-Cpp/lib" libdllCBox.a

Main.o(.text+0x81):Main.cpp: undefined reference to `_imp___ZN4CBoxC1Eddd'
Main.o(.text+0x95):Main.cpp: undefined reference to `_imp___ZN4CBox6VolumeEv'
Main.o(.text+0xbe):Main.cpp: undefined reference to `_imp___ZN4CBoxD1Ev'
Main.o(.text+0xea):Main.cpp: undefined reference to `_imp___ZN4CBoxD1Ev'
collect2: ld returned 1 exit status
make.exe: *** [Boxes.exe] Error 1
Execution terminated


Compiler Tab
==============================================
[Linker error] undefined reference to `_imp___ZN4CBoxC1Eddd'
[Linker error] undefined reference to `_imp___ZN4CBox6VolumeEv'
[Linker error] undefined reference to `_imp___ZN4CBoxD1Ev'
[Linker error] undefined reference to `_imp___ZN4CBoxD1Ev'
ld returned 1 exit status
C:\Code\Dev-Cpp\Projects\dllCBox\Makefile.win [Build Error] [Boxes.exe] Error 1

By the way, I noted from the above Make file that the apparent linker line was...

-L"C:/Dev-Cpp/lib" libdllCBox.a

and that got me to wandering what directory the linker was looking to find libdllCBox.a, so I pasted a copy of it right in the compiler's lib directory along with all the other compiler libs, but it didn't do any good.

Also, I might point out that the above techniques I've described of adding the export lib from the dll to the parameters list box under Linker Settings works fine in Dev C++ or CodeBlocks when it is simple functions being exported from the dll; however, it most
certainly doesn't work for exporting classes and that is why I'm asking. I simply don't know how to do it. I expect its some little simple thingie/setting somewhere, and I'd love to know what it is. Can anyone help me with this?

I did a search here at daniweb and came with some discussion of this issue with regard to Microsoft compilers, but didn't find anything about the GNU stuff. Here is that link...

Exporting Class From dll

http://www.codeproject.com/KB/cpp/howto_export_cpp_classes.aspx

Recommended Answers

All 10 Replies

why is that class declared extern "C" ? C programs can't call c++ classes, to that declaration is pointless.

I was able to do it with Code::Blocks. This is nearly identical to the way I build them with Microsoft compilers. I started out by using the class exactly like you posted it (except for the extern "C" part). Then then it dawned on me that when all the methods are inlined like you have them you don't need that dll at all. So I split the implementation code into its own *.cpp file to force use of the DLL's *.a file

I put the CBox class in its own header file then used that same file in both the dll and application program.

// This is cbox.cpp, which is included in the DLL project.  That puts
// the code for the class into the *.a file which is linked with the
// application program.
#include "cbox.h"

CBox::CBox()
 {
     m_Length = m_Width = m_Height = 0;
 }

CBox::CBox(double dblLen, double dblWidth, double dblHeight)
 {
    std::cout << "Called CBox() Constructor\n";
    m_Length=dblLen;
    m_Width=dblWidth;
    m_Height=dblHeight;
 }

CBox::~CBox()
 {
    std::cout << "Called CBox() Destructor\n";
 }

 double CBox::Volume()
 {
    return m_Length*m_Width*m_Height;
 }
//
// This is the header file that is included in both the DLL and 
// application project.  Code::Blocks IDE defines DLL_EXPORT when
// a new DLL project is created, and I used that macro to determine
// whether the class is exported or imported.
//
#ifndef CBOX_H
#define CBOX_H

#ifndef DLL_EXPORT
#ifdef BUILD_DLL
    #define DLL_EXPORT __declspec(dllexport)
#else
    #define DLL_EXPORT __declspec(dllimport)
#endif // BUILD_DLL
#endif // DLL_EXPORT

#include <iostream>


class DLL_EXPORT CBox
{
 public:
 CBox();
 CBox(double dblLen, double dblWidth, double dblHeight);
 ~CBox();
 double Volume();

 private:
    double m_Length;
    double m_Width;
    double m_Height;

 };

#endif

Thanks a lot for looking at this AncientDragon! You've helped me before too!

Its getting late here so I'll have to experiment with this tomorrow morn I fear. However, this intrigued me...

...then it dawned on me that when all the methods are inlined like you have them you don't need that dll at all.

I don't quite understand. By inlining the functions they don't get exported or references put in the *.a file??? Even when __declspec(dllexport) is used? Humm.

I don't quite understand. By inlining the functions they don't get exported or references put in the *.a file??? Even when __declspec(dllexport) is used? Humm.

That's right because there's nothing in the DLL to export, unless objects of that class are created in the DLL, then they can of course be exported.

Thanks again Ancient Dragon! It works for me now in Code::Blocks & Dev C++.

I'd have never thought of that myself. My mind just wasn't going in that direction. Funny how the extern "C" caused it to work with the MS compilers. Removing that there caused it to fail.

Usually if you are loading the dll at runtime you can use a factory function and a base class to get derived class instances from the dll. But you can't export classes themselves.

>>But you can't export classes themselves.

Funny -- I've been doing that for years, and even posted the example in this thread :)

Really, I think that got to be a troll. :D. C++ has no way of representing type definitions at runtime AFAIK (At least to represent classes like this.). Either you have to include the header file for the class, or u don't have it.

Really, I think that got to be a troll. :D. C++ has no way of representing type definitions at runtime AFAIK (At least to represent classes like this.). Either you have to include the header file for the class, or u don't have it.

Of course you have to include the header file that contains the class declaration. You apparently didn't read my original post (#3) in this thread. class DLL_EXPORT CBox is exactly what does the job of exporting the entire class.

My bad. :D

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.