How to call a post-implemented function (e.g., function pointers or virtual functions implemented in the consuming application) with a complex return type from a DLL function?
I tried the following scheme but got errors.
Test.h:
#ifdef _DLL_IMPL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
typedef string (*test)(void);
extern DLL_EXPORT test __test;
DLL_EXPORT int launch();
Test.cpp:
#define _DLL_IMPL
#include "Test.h"
test __test = 0;
int launch()
{
string a = __test();
return 0;
}
And the consuming application goes like:
Main.cpp:
#include "Test.h"
#pragma comment(lib, "Test.lib")
string test_impl()
{
string a = "test";
return a;
}
int main(int args, char** argv)
{
__test = &test_impl;
return launch();
}
And I got a subsequent error message:
Windows has triggered a breakpoint in TestRun.exe.
This may be due to a corruption of the heap, which indicates a bug in
TestRun.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while TestRun.exe has focus.
The output window may have more diagnostic information.
I don't know what exactly was going on. Error also occurred when I tried a return type of a char pointer, which would be created in the consuming application using a new operator and would be freed in a DLL function using a delete[] operator.
Can someone explain the reason why the error happens and suggest me some solution to this scheme? Thank you!
Passing C++ objects between exe and dll is really not a good idea, more so if the object is based on a template class and/or has inlined methods, and even more so if the object allocates memory internally. If you need that kind of interface between your application and the library then I recommend that you switch your dll to a static library, then you'll avoid most issues.
If you need to keep the dll as a dll, then I recommend that you only pass native types between exe and dll. In your example, switching all the usages of string to char* will likely address the crashes.
Also take good advice from Jim Rhodes and declare an explicit calling convention, even if you found that that was not the problem in this particular case.
Perhaps you have a calling convention mismatch. Maybe string test_impl() should be string __stdcall test_impl().
You very likely are linking with different versions of the C runtime libraries, preventing shared heap use. Make sure that both the app and dll are linked with the same 'flavor' (dynamic or static) of the C runtime libraries - if you aren't sure which one to pick, set them both to dynamic.
See also Strange problems with new/delete in an app that uses my DLL.
What you really want to export/import is not clear. You export test_impl from main.cpp and import launch in main.cpp from test.cpp
Anyway, you should probably export also classes (std::string).
The following code works perfectly:
//test.cpp
typedef __declspec(dllimport) std::string (*test)(void);
extern __declspec(dllexport) test __test;
test __test = 0;
extern __declspec(dllexport) int launch() { std::string a = __test();
std::cout << a << std::endl ;
return 0; }
// main.cpp
typedef __declspec(dllexport) std::string (*test)(void);
extern __declspec(dllimport) test __test;
extern __declspec(dllimport) test __test;
__declspec(dllimport) int launch();
__declspec(dllexport)
std::string test_impl() {
std::string a = "test";
return a; }
int main(int args, char** argv) {
__test = &test_impl;
return launch(); }
Check however that both projects are compiled with the same model (/MTd, /Mt)
Related
I am developping a C++ DLL with a C wrapper in order to use it in Python and C#. So I create on Visual Studio a project (DLL) to develop and compile it. No problem here. I even can use my DLL on Python without trouble.
But, on Visual, I want to create another project in the same solution as the DLL to test the DLL too.
So I created the second project (Win32 Windows Application), added the .h to the header files, added the link to the .lib file I added in the folder of the test project, but when I try to compile it, I have errors about LNK2019, beginning with the constructor:
error LNK2019: unresolved external symbol "public: __cdecl Projet::Projet(void)" (??Projet##QEAA#XZ) referenced in function main
DLL = Projet / Test = Projet_Test
Projet.h
#pragma once
#include "Projet_inc.h"
class Projet
{
public:
Projet();
~Projet();
int multiply(int arg1, int arg2);
int result;
};
Projet_inc.h
#ifdef PROJET_EXPORTS
# define EXPORT __declspec(dllexport)
#else
# define EXPORT __declspec(dllimport)
#endif
#define CALLCONV_API __stdcall
#ifdef __cplusplus
extern "C" // C wrapper
{
#endif
typedef struct Projet Projet; // make the class opaque to the wrapper
EXPORT Projet* CALLCONV_API cCreateObject(void);
EXPORT int CALLCONV_API cMultiply(Projet* pDLLobject, int arg1, int arg2);
#ifdef __cplusplus
}
#endif
Projet.cpp
#include "stdafx.h"
#include "Projet.h"
Projet::Projet() {}
Projet::~Projet() {}
int Projet::multiply(int arg1, int arg2) {
result = arg1 * arg2;
return result;
}
Projet* EXPORT CALLCONV_API cCreateObject(void)
{
return new Projet();
}
int EXPORT CALLCONV_API cMultiply(Projet* pDLLtest, int arg1, int arg2)
{
if (!pDLLtest)
return 0;
return pDLLtest->multiply(arg1, arg2);
}
Projet_Test.cpp
// Projet_Test.cpp : définit le point d'entrée pour l'application console.
//
#include "stdafx.h"
#include "Projet.h"
int main()
{
Projet object;
return 0;
}
On Visual, I select the test project as startup project for information. And I look a lot of posts on SO but I didn't find the solution for now. Thank you in advance.
You need to __declspec(dllexport) all functions that you want to call directly, not just the C ones.
In your example, you should be able to correctly call the C wrapper functions cCreateObject and cMultiply, as those were exported correctly, but you will not be able to call the underlying C++ functions like Projet::Projet() and Projet::~Projet().
You have two ways of solving this: You can change these functions to inline functions and move their implementation to the header. That way, the client project will no longer invoke the code from the DLL for those functions, but instead just compile the inline definitions directly itself. This is obviously not a sensible approach in general. Alternatively, mark your C++ member functions with __declspec(dllexport), just as you did with the C functions.
Note that Visual Studio has a tendency of breaking the C++ ABI between versions, so you need to make sure that the compiler version you used for compiling the dll is compatible with the one you used for compiling the client application. This is not an issue if both parts are compiled with the same Visual Studio version or if you stick with a plain C interface.
First, the error about the missing symbol EpsCndCoreDll seems to be out of context here and you should rather be getting a compile error about redefining struct as a class (class Projet).
Probably you need to use something like:
class Projet;
typedef Projet* PProjet;
and use PProject as the opaque handle further on.
You also need to export the Projet class like:
class EXPORT Projet
to be able to instantiate that class by a client or add a factory function that returns a reference.
Make sure that you have added the DLL reference to your DLL.
Most of my C/C++ development involves monolithic module files and absolutely no classes whatsoever, so usually when I need to make a DLL with accessible functions I just export them using the standard __declspec(dllexport) directive. Then access them either dynamically via LoadLibrary() or at compile time with a header and lib file.
How do you do this when you want to export an entire class (and all it's public methods and properties)?
Is it possible to dynamically load that class at runtime and if so, how?
How would you do it with a header and lib for compile time linking?
What about late-binding? As in loading
it with LoadLibrary() and
GetProcAddress() ? I'm used being able
to load the library at run time and it
would be great if you could do that
here.
So there are two ways to load the DLL. The first is to reference one or more symbols from the DLL (your classname, for example), supply an appropriate import .LIB and let the linker figure everything out.
The second is to explicitly load the DLL via LoadLibrary.
Either approach works fine for C-level function exports. You can either let the linker handle it or call GetProcAddress as you noted.
But when it comes to exported classes, typically only the first approach is used, i.e., implicitly link to the DLL. In this case the DLL is loaded at application start time, and the application fails to load if the DLL can't be found.
If you want to link to a class defined in a DLL, and you want that DLL to be loaded dynamically, sometime after program initiation, you have two options:
Create objects of the class using a special factory function, which internally will have to use (a tiny bit of) assembler to "hook up" newly created objects to their appropriate offsets. This has to be done at run-time AFTER the DLL has been loaded, obviously. A good explanation of this approach can be found here.
Use a delay-load DLL.
All things considered... probably better to just go with implicit linking, in which case you definitely want to use the preprocessor technique shown above. In fact, if you create a new DLL in Visual Studio and choose the "export symbols" option these macros will be created for you.
Good luck...
When you build the DLL and the module that will use the DLL, have some kind of #define that you can use to distinguish between one and the other, then you can do something like this in your class header file:
#if defined( BUILD_DLL )
#define IMPORT_EXPORT __declspec(dllexport)
#else
#define IMPORT_EXPORT __declspec(dllimport)
#endif
class IMPORT_EXPORT MyClass {
...
};
Edit: crashmstr beat me to it!
Adding a simple working example for exporting a C++ class from a DLL :
The given below example gives you only a short overview of how dll and exe can interact each other (self explanatory ) but it needs more things to add for changing into a production code.
Full sample example is divided in to two part
A. Creating a .dll library (MyDLL.dll)
B. Creating an Application which uses .dll library (Application).
A. .dll project file (MyDLL.dll):
1. dllHeader.h
#ifdef MYDLL_EXPORTS
#define DLLCALL __declspec(dllexport) /* Should be enabled before compiling
.dll project for creating .dll*/
#else
#define DLLCALL __declspec(dllimport) /* Should be enabled in Application side
for using already created .dll*/
#endif
// Interface Class
class ImyMath {
public:
virtual ~ImyMath() {;}
virtual int Add(int a, int b) = 0;
virtual int Subtract(int a, int b) = 0;
};
// Concrete Class
class MyMath: public ImyMath {
public:
MyMath() {}
int Add(int a, int b);
int Subtract(int a, int b);
int a,b;
};
// Factory function that will return the new object instance. (Only function
// should be declared with DLLCALL)
extern "C" /*Important for avoiding Name decoration*/
{
DLLCALL ImyMath* _cdecl CreateMathObject();
};
// Function Pointer Declaration of CreateMathObject() [Entry Point Function]
typedef ImyMath* (*CREATE_MATH) ();
2. dllSrc.cpp
#include "dllHeader.h"
// Create Object
DLLCALL ImyMath* _cdecl CreateMathObject() {
return new MyMath();
}
int MyMath::Add(int a, int b) {
return a+b;
}
int MyMath::Subtract(int a, int b) {
return a-b;
}
B. Application Project which load and link the already created .dll file:
#include <iostream>
#include <windows.h>
#include "dllHeader.h"
int main()
{
HINSTANCE hDLL = LoadLibrary(L"MyDLL.dll"); // L".\Debug\MyDLL.dll"
if (hDLL == NULL) {
std::cout << "Failed to load library.\n";
}
else {
CREATE_MATH pEntryFunction = (CREATE_MATH)GetProcAddress(hDLL,"CreateMathObject");
ImyMath* pMath = pEntryFunction();
if (pMath) {
std::cout << "10+10=" << pMath->Add(10, 10) << std::endl;
std::cout << "50-10=" << pMath->Subtract(50, 10) << std::endl;
}
FreeLibrary(hDLL);
}
std::cin.get();
return 0;
}
I use some macros to mark the code for import or export
#ifdef ISDLL
#define DLL __declspec(dllexport)
#endif
#ifdef USEDLL
#define DLL __declspec(dllimport)
#endif
Then declare the class in a header file:
class DLL MyClassToExport { ... }
Then #define ISDLL in the libary, and USEDLL before including the header file in the place you want to use the class.
I don't know if you might need to do anything differently for working with LoadLibrary
Recently I asked myself exactly the same question, and summarized my findings in a blog post. You may find it useful.
It covers exporting C++ classes from a DLL, as well as loading them dynamically with LoadLibrary, and discusses some of the issues around that, such as memory management, name mangling and calling conventions.
If you're willing to put a vtable in the class you're exporting, you can export a function that returns an interface and implement the class in the .dll, then put that in the .def file. You might have to do some declaration trickery, but it shouldn't be too hard.
Just like COM. :)
I'm trying to increase my understanding of basic library linking, dependencies, etc. I created a Visual Studio solution with three projects
Static lib using /MTd with a single class (Foo), one method int GetNum() { return 5; }
Shared dll using /MDd with a single class (Bar), one method int GetNum() { Foo f; return f.GetNum(); }
Win32 console app. That calls Bar b; std::cout << b.GetNum() << std::endl
When I tried to build this, it complained it couldn't find my dll's associated lib. Did a little research, saw that I needed to add __declspec(dllexport) to my GetNum() method and I'd get a .lib. Cool.
Next hurtle was the console app said it couldn't find the static lib for Foo. I added it to my references and it all build and ran fine.
My question is - why does my exe need to know anything about Foo? I wanted to effectively "bake" in all my dependencies into the dll so I could just share that, link into it, and be good to go.
Is this just not how the language works or a setting / pattern I'm missing? My end goal is to be able to build a dll that encapsulates the usage of third party .lib's and not have the client app need to worry about adding references to all of them.
Update
Here is most of the code.
// ---------------------- Lib (e.g. Foo)
#pragma once
class MathLib
{
public:
MathLib(void);
~MathLib(void);
int GetNum() { return 83; }
};
// ---------------------- DLL (e.g. Bar)
#pragma once
#ifdef CONSOLETEST_EXPORT
#define CONSOLETEST_API __declspec(dllexport)
#else
#define CONSOLETEST_API __declspec(dllimport)
#endif
#include "MathLib.h"
class MathDll
{
public:
__declspec(dllexport) MathDll(void);
__declspec(dllexport) ~MathDll(void);
__declspec(dllexport) int GetNumFromDyn()
{
MathLib m;
return m.GetNum();
}
};
// ---------------------- exe
int _tmain(int argc, _TCHAR* argv[])
{
MathDll m;
std::cout << "num is " << m.GetNumFromDyn() << std::endl;
return 0;
}
With C/C++, it's very important to structure your code properly across headers (e.g. h, hpp, hxx, h++, etc.) and translation units (usually called sources, e.g. c, cpp, cxx, c++, etc.). When you design a library, you should be constantly thinking what belongs to its interface (i.e. supposed to be seen by consumers) and what belongs to its implementation (i.e. not supposed to be seen by consumers).
Remember the rule of thumb - all symbols that are present in any header will be seen by consumers (if included), and, as a result, required by consumers to be resolved during linking stage at some point in time later!
This is essentially what happened to you in your toy example. So let's fix it by using a simple rule, which you should remember by heart: Put as much as possible into translation units, i.e. keep headers minimal. Now let's use your example to show how it works:
MathLib.hpp:
#pragma once
class MathLib {
public:
MathLib();
~MathLib();
int GetNum();
};
MathLib.cpp:
#include "MathLib.hpp"
MathLib::MathLib() {}
MathLib::~MathLib() {}
int MathLib::GetNum() { return 83; }
Now build MathLib.cpp as static library.
MathDll.hpp:
#pragma once
#ifdef CONSOLETEST_EXPORT
# define CONSOLETEST_API __declspec(dllexport)
#else
# define CONSOLETEST_API __declspec(dllimport)
#endif
class CONSOLETEST_API MathDll {
public:
MathDll();
~MathDll();
int GetNumFromDyn();
};
MathDll.cpp:
#include "MathDll.hpp"
#include "MathLib.hpp"
MathDll::MathDll() {}
MathDll::~MathDll() {}
int MathDll::GetNumFromDyn() {
MathLib m;
return m.GetNum();
}
Now build MathDll.cpp as dynamic-link library (DLL) and don't forget to add definition CONSOLETEST_EXPORT during its build, so that CONSOLETEST_API is __declspec(dllexport), and, as a result, an import library with exported symbols (i.e. the MathDll class and its methods) is generated for the DLL. On MSVC you can achieve this by adding /DCONSOLETEST_API to the invocation of compiler. Finally, when building this DLL, certainly link it with previously built static library, MathLib.lib.
NOTE: It's better to export the whole class like I did above with class CONSOLETEST_API MathDll, rather than export all methods individually.
main.cpp:
#include "MathDll.hpp"
#include <iostream>
int _tmain(int argc, _TCHAR* argv[]) {
MathDll m;
std::cout << "num is " << m.GetNumFromDyn() << std::endl;
return 0;
}
Now build main.cpp as console application and only link it with previously built import library for DLL, MathDll.lib.
Notice how the problem is gone because I've got rid of transitive dependency to MathLib (through MathDll.hpp) from main.cpp, since now the #include "MathLib.hpp" inclusion is done in the translation unit MathDll.cpp (because it's actually only needed there according to above rule), and is therefore built into binary artifact (DLL in this case) and not present in its interface.
Understanding all of this is really important for proper native software development with C/C++, so it's really good that you ask this question beforehand. I meet people who don't know/understand this quite often, what results in complete nightmare for them (amateurs), and us, when we have to deal with that crappy software they write...
Consider the case when MathLib is a part of MathDll class.
//MathDll.h
#include "MathLib.h"
class MathDll
{
private:
MathLib m;
public:
__declspec(dllexport) MathDll(void);
__declspec(dllexport) ~MathDll(void);
__declspec(dllexport) int GetNumFromDyn()
{
return m.GetNum();
}
};
you will have to now include MathLib.h into your MathDll.h, which propagates to the console app too.
You can avoid this...
By using PIMPL idiom to encapsulate everything into the DLL.
Provide the forward declaration of the class MathLib in the header and the rest of the implemenation hidden in the Dll. You can also consider exporting the whole class.
//------------MathDll.h
// we do not include "MathLib.h" here. include it in the MathDll.cpp only
class MathLib;
class __declspec(dllexport) MathDll
{
private:
MathLib* m;
public:
MathDll(void);
~MathDll(void);
int GetNumFromDyn();
};
//--------------MathDll.cpp
#include "MathLib.h"
#include "MathDll.h"
MathDll::MathDll(void)
{
m = new MathLib();
}
MathDll::~MathDll(void)
{
delete m;
}
int MathDll::GetNumFromDyn()
{
return m->GetNum();
}
Most of my C/C++ development involves monolithic module files and absolutely no classes whatsoever, so usually when I need to make a DLL with accessible functions I just export them using the standard __declspec(dllexport) directive. Then access them either dynamically via LoadLibrary() or at compile time with a header and lib file.
How do you do this when you want to export an entire class (and all it's public methods and properties)?
Is it possible to dynamically load that class at runtime and if so, how?
How would you do it with a header and lib for compile time linking?
What about late-binding? As in loading
it with LoadLibrary() and
GetProcAddress() ? I'm used being able
to load the library at run time and it
would be great if you could do that
here.
So there are two ways to load the DLL. The first is to reference one or more symbols from the DLL (your classname, for example), supply an appropriate import .LIB and let the linker figure everything out.
The second is to explicitly load the DLL via LoadLibrary.
Either approach works fine for C-level function exports. You can either let the linker handle it or call GetProcAddress as you noted.
But when it comes to exported classes, typically only the first approach is used, i.e., implicitly link to the DLL. In this case the DLL is loaded at application start time, and the application fails to load if the DLL can't be found.
If you want to link to a class defined in a DLL, and you want that DLL to be loaded dynamically, sometime after program initiation, you have two options:
Create objects of the class using a special factory function, which internally will have to use (a tiny bit of) assembler to "hook up" newly created objects to their appropriate offsets. This has to be done at run-time AFTER the DLL has been loaded, obviously. A good explanation of this approach can be found here.
Use a delay-load DLL.
All things considered... probably better to just go with implicit linking, in which case you definitely want to use the preprocessor technique shown above. In fact, if you create a new DLL in Visual Studio and choose the "export symbols" option these macros will be created for you.
Good luck...
When you build the DLL and the module that will use the DLL, have some kind of #define that you can use to distinguish between one and the other, then you can do something like this in your class header file:
#if defined( BUILD_DLL )
#define IMPORT_EXPORT __declspec(dllexport)
#else
#define IMPORT_EXPORT __declspec(dllimport)
#endif
class IMPORT_EXPORT MyClass {
...
};
Edit: crashmstr beat me to it!
Adding a simple working example for exporting a C++ class from a DLL :
The given below example gives you only a short overview of how dll and exe can interact each other (self explanatory ) but it needs more things to add for changing into a production code.
Full sample example is divided in to two part
A. Creating a .dll library (MyDLL.dll)
B. Creating an Application which uses .dll library (Application).
A. .dll project file (MyDLL.dll):
1. dllHeader.h
#ifdef MYDLL_EXPORTS
#define DLLCALL __declspec(dllexport) /* Should be enabled before compiling
.dll project for creating .dll*/
#else
#define DLLCALL __declspec(dllimport) /* Should be enabled in Application side
for using already created .dll*/
#endif
// Interface Class
class ImyMath {
public:
virtual ~ImyMath() {;}
virtual int Add(int a, int b) = 0;
virtual int Subtract(int a, int b) = 0;
};
// Concrete Class
class MyMath: public ImyMath {
public:
MyMath() {}
int Add(int a, int b);
int Subtract(int a, int b);
int a,b;
};
// Factory function that will return the new object instance. (Only function
// should be declared with DLLCALL)
extern "C" /*Important for avoiding Name decoration*/
{
DLLCALL ImyMath* _cdecl CreateMathObject();
};
// Function Pointer Declaration of CreateMathObject() [Entry Point Function]
typedef ImyMath* (*CREATE_MATH) ();
2. dllSrc.cpp
#include "dllHeader.h"
// Create Object
DLLCALL ImyMath* _cdecl CreateMathObject() {
return new MyMath();
}
int MyMath::Add(int a, int b) {
return a+b;
}
int MyMath::Subtract(int a, int b) {
return a-b;
}
B. Application Project which load and link the already created .dll file:
#include <iostream>
#include <windows.h>
#include "dllHeader.h"
int main()
{
HINSTANCE hDLL = LoadLibrary(L"MyDLL.dll"); // L".\Debug\MyDLL.dll"
if (hDLL == NULL) {
std::cout << "Failed to load library.\n";
}
else {
CREATE_MATH pEntryFunction = (CREATE_MATH)GetProcAddress(hDLL,"CreateMathObject");
ImyMath* pMath = pEntryFunction();
if (pMath) {
std::cout << "10+10=" << pMath->Add(10, 10) << std::endl;
std::cout << "50-10=" << pMath->Subtract(50, 10) << std::endl;
}
FreeLibrary(hDLL);
}
std::cin.get();
return 0;
}
I use some macros to mark the code for import or export
#ifdef ISDLL
#define DLL __declspec(dllexport)
#endif
#ifdef USEDLL
#define DLL __declspec(dllimport)
#endif
Then declare the class in a header file:
class DLL MyClassToExport { ... }
Then #define ISDLL in the libary, and USEDLL before including the header file in the place you want to use the class.
I don't know if you might need to do anything differently for working with LoadLibrary
Recently I asked myself exactly the same question, and summarized my findings in a blog post. You may find it useful.
It covers exporting C++ classes from a DLL, as well as loading them dynamically with LoadLibrary, and discusses some of the issues around that, such as memory management, name mangling and calling conventions.
If you're willing to put a vtable in the class you're exporting, you can export a function that returns an interface and implement the class in the .dll, then put that in the .def file. You might have to do some declaration trickery, but it shouldn't be too hard.
Just like COM. :)
Most of my C/C++ development involves monolithic module files and absolutely no classes whatsoever, so usually when I need to make a DLL with accessible functions I just export them using the standard __declspec(dllexport) directive. Then access them either dynamically via LoadLibrary() or at compile time with a header and lib file.
How do you do this when you want to export an entire class (and all it's public methods and properties)?
Is it possible to dynamically load that class at runtime and if so, how?
How would you do it with a header and lib for compile time linking?
What about late-binding? As in loading
it with LoadLibrary() and
GetProcAddress() ? I'm used being able
to load the library at run time and it
would be great if you could do that
here.
So there are two ways to load the DLL. The first is to reference one or more symbols from the DLL (your classname, for example), supply an appropriate import .LIB and let the linker figure everything out.
The second is to explicitly load the DLL via LoadLibrary.
Either approach works fine for C-level function exports. You can either let the linker handle it or call GetProcAddress as you noted.
But when it comes to exported classes, typically only the first approach is used, i.e., implicitly link to the DLL. In this case the DLL is loaded at application start time, and the application fails to load if the DLL can't be found.
If you want to link to a class defined in a DLL, and you want that DLL to be loaded dynamically, sometime after program initiation, you have two options:
Create objects of the class using a special factory function, which internally will have to use (a tiny bit of) assembler to "hook up" newly created objects to their appropriate offsets. This has to be done at run-time AFTER the DLL has been loaded, obviously. A good explanation of this approach can be found here.
Use a delay-load DLL.
All things considered... probably better to just go with implicit linking, in which case you definitely want to use the preprocessor technique shown above. In fact, if you create a new DLL in Visual Studio and choose the "export symbols" option these macros will be created for you.
Good luck...
When you build the DLL and the module that will use the DLL, have some kind of #define that you can use to distinguish between one and the other, then you can do something like this in your class header file:
#if defined( BUILD_DLL )
#define IMPORT_EXPORT __declspec(dllexport)
#else
#define IMPORT_EXPORT __declspec(dllimport)
#endif
class IMPORT_EXPORT MyClass {
...
};
Edit: crashmstr beat me to it!
Adding a simple working example for exporting a C++ class from a DLL :
The given below example gives you only a short overview of how dll and exe can interact each other (self explanatory ) but it needs more things to add for changing into a production code.
Full sample example is divided in to two part
A. Creating a .dll library (MyDLL.dll)
B. Creating an Application which uses .dll library (Application).
A. .dll project file (MyDLL.dll):
1. dllHeader.h
#ifdef MYDLL_EXPORTS
#define DLLCALL __declspec(dllexport) /* Should be enabled before compiling
.dll project for creating .dll*/
#else
#define DLLCALL __declspec(dllimport) /* Should be enabled in Application side
for using already created .dll*/
#endif
// Interface Class
class ImyMath {
public:
virtual ~ImyMath() {;}
virtual int Add(int a, int b) = 0;
virtual int Subtract(int a, int b) = 0;
};
// Concrete Class
class MyMath: public ImyMath {
public:
MyMath() {}
int Add(int a, int b);
int Subtract(int a, int b);
int a,b;
};
// Factory function that will return the new object instance. (Only function
// should be declared with DLLCALL)
extern "C" /*Important for avoiding Name decoration*/
{
DLLCALL ImyMath* _cdecl CreateMathObject();
};
// Function Pointer Declaration of CreateMathObject() [Entry Point Function]
typedef ImyMath* (*CREATE_MATH) ();
2. dllSrc.cpp
#include "dllHeader.h"
// Create Object
DLLCALL ImyMath* _cdecl CreateMathObject() {
return new MyMath();
}
int MyMath::Add(int a, int b) {
return a+b;
}
int MyMath::Subtract(int a, int b) {
return a-b;
}
B. Application Project which load and link the already created .dll file:
#include <iostream>
#include <windows.h>
#include "dllHeader.h"
int main()
{
HINSTANCE hDLL = LoadLibrary(L"MyDLL.dll"); // L".\Debug\MyDLL.dll"
if (hDLL == NULL) {
std::cout << "Failed to load library.\n";
}
else {
CREATE_MATH pEntryFunction = (CREATE_MATH)GetProcAddress(hDLL,"CreateMathObject");
ImyMath* pMath = pEntryFunction();
if (pMath) {
std::cout << "10+10=" << pMath->Add(10, 10) << std::endl;
std::cout << "50-10=" << pMath->Subtract(50, 10) << std::endl;
}
FreeLibrary(hDLL);
}
std::cin.get();
return 0;
}
I use some macros to mark the code for import or export
#ifdef ISDLL
#define DLL __declspec(dllexport)
#endif
#ifdef USEDLL
#define DLL __declspec(dllimport)
#endif
Then declare the class in a header file:
class DLL MyClassToExport { ... }
Then #define ISDLL in the libary, and USEDLL before including the header file in the place you want to use the class.
I don't know if you might need to do anything differently for working with LoadLibrary
Recently I asked myself exactly the same question, and summarized my findings in a blog post. You may find it useful.
It covers exporting C++ classes from a DLL, as well as loading them dynamically with LoadLibrary, and discusses some of the issues around that, such as memory management, name mangling and calling conventions.
If you're willing to put a vtable in the class you're exporting, you can export a function that returns an interface and implement the class in the .dll, then put that in the .def file. You might have to do some declaration trickery, but it shouldn't be too hard.
Just like COM. :)