How to use a class in DLL? - c++

Can I put a class inside a DLL?
The class i wrote is this:
class SDLConsole
{
public:
SDLConsole();
~SDLConsole(){};
void getInfo(int,int);
void initConsole(char*, char*, SDL_Surface*, int, int, int);
void sendMsg(char*,int, SDL_Surface*);
void cls(SDL_Surface*);
private:
TTF_Font *font;
SDL_Surface *consoleImg;
int width, pos, height, line, size, ctLine;
SDL_Surface* render(char*,int);
};
I know how to load a DLL and use the function inside a DLL, but how can I put a class inside a DLL? Thank you very much.

If you use run time dynamic linking (uses LoadLibrary to load the dll) you cannot access the class directly, you need to declare a interface for your class and create a function that returns a instance of this class, like this:
class ISDLConsole
{
public:
virtual void getInfo(int,int) = 0;
virtual void initConsole(char*, char*, SDL_Surface*, int, int, int) = 0;
virtual void sendMsg(char*,int, SDL_Surface*) = 0;
virtual void cls(SDL_Surface*) = 0;
};
class SDLConsole: public ISDLConsole
{
//rest of the code
};
__declspec(dllexport) ISDLConsole *Create()
{
return new SDLConsole();
}
Otherwise, if you link the dll during load time, just use the information provided by icecrime: http://msdn.microsoft.com/en-us/library/a90k134d.aspx

Solution suggested by bcsanches,
__declspec(dllexport) ISDLConsole *Create()
{
return new SDLConsole();
}
If you're going to use this approach as suggested by bcsanches, then make sure that you use the following function to delete your object,
__declspec(dllexport) void Destroy(ISDLConsole *instance)
{
delete instance;
}
Define such functions always in pair, as it ensures that you delete your objects from the same heap/memory-pool/etc they were created on. See this pair-functions

You can, and all the information you need are on this page and this page :
#ifdef _EXPORTING
#define CLASS_DECLSPEC __declspec(dllexport)
#else
#define CLASS_DECLSPEC __declspec(dllimport)
#endif
class CLASS_DECLSPEC SDLConsole
{
/* ... */
};
All there is left is to define the preprocessor symbol _EXPORTING when building the DLL.

If you want to expose the data in a class, the above solutions won't cut it. You have to slap a __declspec(dllexport) on the class itself in the DLL compilation, and a __declspec(dllimport) in the module that links to the DLL.
A common technique is to do this (Microsoft wizards produce code like this):
#ifdef EXPORT_API
#define MY_API __declspec(dllexport)
#else
#define MY_API __declspec(dllimport)
#endif
class MY_API MyClass {
...
};
Then make sure EXPORT_API is defined in the DLL project, and make sure it isn't defined in the module that links to the DLL.
If you create a new DLL project in Visual C++ from scratch, and check the check box "Export symbols", some sample code will be generated using this technique.

Related

Export parent and base class in C++

Im trying to create a DLL consisting of C++ classes including inheritance. The DLL is supposed to be accessed by some console application.
Parent class:
paramCalculator.h
#ifdef MY_EXPORTS
#define PARAMCALCULATOR __declspec(dllexport)
#else
#define PARAMCALCULATOR __declspec(dllimport)
#endif
class PARAMCALCULATOR paramCalculator
{
public:
paramCalculator();
~paramCalculator();
float m_current;
};
paramCalculator.cpp
#include "stdafx.h"
paramCalculator::paramCalculator()
{
}
paramCalculator::~paramCalculator()
{
}
Child class:
currentCalculator.h
#ifdef MY_EXPORTS
#define PARAMCALCULATOR __declspec(dllexport)
#else
#define PARAMCALCULATOR __declspec(dllimport)
#endif
class PARAMCALCULATOR currentCalculator :
public paramCalculator
{
public:
currentCalculator();
~currentCalculator();
float m_tubePower = 1500;
float m_tubeCurrent;
void calcCurrent(float vo);
};
currentCalculator.cpp
#include "stdafx.h"
currentCalculator::currentCalculator()
{
}
currentCalculator::~currentCalculator()
{
}
void currentCalculator::calcCurrent(float vo)
{
m_tubeCurrent = m_tubePower / vo;
std::cout << m_tubeCurrent << std::endl;
m_current = m_tubeCurrent;
}
The console application accessing the DLL looks as follows:
#include "paramCalculator.h"
#include "currentCalculator.h"
class tubeCurrent
{
public:
tubeCurrent() {};
~tubeCurrent() {};
void setParam(float v)
{
ab.calcCurrent(v);
m_current = ab.m_tubeCurrent;
}
currentCalculator ab;
float m_current;
};
int main()
{
tubeCurrent ac;
float voltage = 200;
ac.setParam(voltage);
}
When running the console application it shows "7.5" on the output window, which is the expected calculated value for the current. This tells me that accessing the DLL works. However, the variables m_tubeCurrent and m_current have not been changed to value 7.5. Can anyone tell me how to fix this and get both variables to update its values?
During some tests i've found out that as soon as I remove the inheritance relation between both classes, the member variable "m_tubeCurrent" are updated successfully. However, im struggling to find a way to access the member variables when inheritance between both classes is involved.
I've gone through this question but couldn't solve my issue.
Thanks in advance!
Edit:
In order to make myself more clear, here's two images of the debug window within the console application.
Inheritance is included and the calculated values are not assigned to the corresponding variables:
No inheritance resulting in the calculated values being assigned to the corresponding variables:
In the latter one, I have only changed the currentCalculator class definition within the currentCalculator.h file from
class PARAMCALCULATOR currentCalculator :
public paramCalculator:
to
class PARAMCALCULATOR currentCalculator
Both variants calculate the values in the right manner when the DLL is executed, however only the latter one allows me to still access the variables after the DLL has been executed.

Making a static library

I am attempting to make a static library for a piece of code of mine, but cannot figure out how to get it to work.
The exact question is:
What exactly do I need to export and what do I need to import in order to get it to work?:
What I did:
I slapped a __declspec(dllexport) on the class and the 2 function that I need to access from within the class.
__declspec(dllexport) class MyClass {
public:
...
__declspec(dllexport) int functionA() {
...
}
__declspec(dllexport) int functionB() {
...
}
...
};
I then created a header where I import the library (same architecture):
#pragma comment(lib, "MyLib.lib")
And I redefined the class and imported only the things I previously exported (and put them inside a namespace)
namespace MyNamespace {
__declspec(dllimport) class MyClass {
public:
__declspec(dllimport) int functionA();
__declspec(dllimport) int functionB();
};
}
And I attempted to call them, only to be met with unresolved external symbol errors
MyClass m; int a = m.FunctionA();
So,
Do I need to export more code? do I need to export constructors? Do I need to change the function prototype?
Thanks!

C++ | DLL / EXE - How to call another class method from exported class?

I have a project where I want to use DLL.
I am exporting a factory function into my exe:
extern "C" __declspec(dllexport)
BaseInit* __cdecl CreateInterface( void )
{
return new Initializer;
}
This works perfectly. In my Init class I have a method to create another class that I want to use conveniently from my Initializer class:
class IAnotherClass {
public:
virtual void TestFunction();
...
class AnotherClass : public IAnotherClass {
public:
void TestFunction();
...
class Initializer : public BaseInit
{
IAnotherClass* Create(void)
{
return new AnotherClass;
}
...
This also seems to work. I'm getting a non-NULL pointer. However when trying to call TestFunction from this class (in my exe-program) I'm getting :
LNK2001 unresolved external symbol "public: virtual void __cdecl
AnotherClass::TestFunction(void)"
(?TestFunction#AnotherClass##UEAAXXZ)
void AnotherClass::TestFunction -body is in separate .cpp -file in my DLL project
Am I doing this wrong and I actually need separate factory functions for every different class instance? Is it even possible to do it this way?
You need to add __declspec(dllexport) to every class and function you want to be available outside of your dll, you don't need to mark methods as long as the containing class is exported.
Note in classes the declspec goes between class and the class name:
class __declspec(dllexport) Exported
{
};
You'll also need a macro defined which switches your headers between __declspec(dllexport) and __declspec(dllimport) depending on whether you are building your dll or exe, e.g.:
#ifdef BUILDING_MYDLL
#define MYDLL_EXPORT __declspec(dllexport)
#else
#define MYDLL_EXPORT __declspec(dllimport)
#endif
class MYDLL_EXPORT Exported
{
};

Is it possible to have application level singleton?

I've got simple singleton with
class Options {
private:
Options()
{};
Options(Options const&);
void operator=(Options const&);
public:
static Options& get()
{
static Options INSTANCE;
return INSTANCE;
}
};
I've got this definition in header in shared library A
but when I call get() first from application B I see how there instance is creating and then I call methods from shared library C and using get() there I'm getting yet another instance...
How can I have something alike Application level singleton? (is it something with extern keyword?)
It should work under windows provided:
you consistently use __declspec(dllexport) for export and __declspec(dllimport) for import
the implementation of Options::get() is moved in a cpp file so that it only exists in the DLL.
Here is an example :
options.dll build with OPTIONS_EXPORT symbol defined:
options.h:
#pragma once
#ifdef OPTIONS_EXPORTS
#define DLLAPI __declspec(dllexport)
#else
#define DLLAPI __declspec(dllimport)
#endif
class DLLAPI Options
{
private:
Options()
{};
Options(Options const&);
void operator=(Options const&);
public:
static Options& get();
int val;
};
options.cpp:
#include "Options.h"
Options& Options::get()
{
static Options INSTANCE;
return INSTANCE;
}
A dummy c.dll using options.dll build with C_EXPORT symbol defined and linked with options.lib:
c.h:
#pragma once
#ifdef C_EXPORTS
#define dll __declspec(dllexport)
#else
#define dll __declspec(dllimport)
#endif
#include "../a/options.h"
namespace C {
dll Options& relay();
};
c.cpp:
#include "c.h"
Options& C::relay() {
Options& opt = Options::get();
return opt;
}
And a minimal main linked with both options.dll and c.dll:
#include <iostream>
#include "../a/options.h"
#include "../c/c.h"
int main() {
Options& o1 = Options::get();
o1.val = 12;
Options& o2 = C::relay();
std::cout << ((o1.val == o2.val) ? "Ok" : "Ko") << std::endl;
return 0;
}
Output is as expected: Ok
The issue is that all of your applications and libraries compile their own copy of your class into the library, since you tell all of them how the class should look.
First of, start by moving the implementation of theget function into the source file. After this is done and you compile you should see that your shared libraries does not know how the function should look and they will not compile (linker errors except in the library that contains the class).
From there start to fix the compilation by letting the application and other libraries know where to link the function from.
On windows you need to export the class in the library that it is implemented in using __declspec(dllexport).
On the library and possibly the application you need to use __declspec(dllimport) to import the class.
On Linux this should not be necessary.

how to use a c++ class that is exported to a dll?

I have exported a C++ class and now i want to use its public member function. how i can do it?
I want to have dynamic binding. My exported class looks like this
#ifdef MAKEDLL
#define DECLDIREXP __declspec(dllexport)
#else
#define DECLDIREXP __declspec(dllimport)
#endif
class DECLDIREXP xyz
{
public:
void printing();
void printing(int a);
};
using namespace std;
void xyz::printing()
{
cout<<"hello i donot take any argument";
}
void xyz::printing(int a)
{
cout<<"hello i take "<< a <<"as argument";
}
it seems you are almost there.
When building the project generating the dll, make sure MAKEDLL is defined for the linker, and the other way round in projects consuming the dll.
By the way MAKEDLL is probably a bad Name, but MAKEFOODLL if your dll is called foo a better one