I encountered a strange behavior for an msvc c++ build while compiling two shared libraries and an executable. The complete setup can be found on GitHub
Information:
platform toolset is v143
4 projects: 1 header only, 2 DLL`s, 1 executable
The 4 projects are:
HeaderOnlyInterface (header only)
Implementation (DLL)
Factory (DLL)
SharedLibsTest (EXE)
Projects 2 - 4 can include all header files from HeaderOnlyInterface.
HeaderOnlyInterface consists of two header files:
DLLExport.h
#pragma once
#ifdef MAKEDLL
# define EXPORT __declspec(dllexport)
#else
# define EXPORT __declspec(dllimport)
#endif
IFoo.h
#pragma once
#include "DLLExport.h"
class EXPORT IFoo
{
public:
virtual ~IFoo() = 0 {}
virtual void Bar() = 0;
};
The next project is Implementation which implements the defined abstract class. This class has MAKEDLL defined as PREPROCESSOR macro. I only show the header because the source is unnecessary:
Foo.h
#pragma once
#include <IFoo.h>
class EXPORT Foo : public IFoo
{
public:
void Bar() override;
};
Going on to Factory, which also defines MAKEDLL and links against Implementation.lib, I have these two files:
FooFactory.h
#pragma once
#include <IFoo.h>
class EXPORT FooFactory
{
public:
static IFoo* Create();
};
FooFactory.cpp
#include "FooFactory.h"
#include <Foo.h>
IFoo* FooFactory::Create()
{
return new Foo();
}
And at the last, I have a main method in an Executable, which links against Factory.lib:
#include <FooFactory.h>
int main()
{
auto* foo = FooFactory::Create();
foo->Bar();
delete foo;
}
For me, the strange thing is, that everything compiles and works fine until now. I have no compile or linker warnings.
The strange thing for me is the compilation and linkage of Factory.lib (and NOT against Implementation.lib).
This library imports a class and exports it also and I do not know why it works. I try to explain my thinking by providing in (pseudo-) code what happens if FooFactory.cpp is pre-processed:
class __declspec(dllexport) IFoo
{
public:
virtual ~IFoo() = 0 {}
virtual void Bar() = 0;
};
class __declspec(dllexport) FooFactory
{
public:
static IFoo* Create();
};
class __declspec(dllexport) Foo : public IFoo
{
public:
void Bar() override;
};
IFoo* FooFactory::Create()
{
return new Foo();
}
The macro is the same for all compiled libs meaning that Factory.lib is exporting all classes. But it does not compile the implementation of Foo::Bar(). Also, it is somehow able to import the implementation because the code works fine. I am not sure why it works, and what really happens under the hood.
If someone could lighten me up on this behavior and also maybe could explain why I should do it not like this or maybe why this is a good idea to do it like this, that would be really helpful.
Thanks!
I got a weird C++ question and have no idea how to resolve it.
I have a public header:
// a.h
#ifdef A_EXPORTS
#define A_API __declspec(dllexport)
#else
#define A_API __declspec(dllimport)
#endif
struct A_API IWorker
{
virtual bool foo() { return false; }
};
I built a.DLL with -DA_EXPORTS.
But my test.exe just needs a mocked IWorker.
// test.cpp
#include "a.h"
class CMockWorker : public IWorker
{
public:
bool foo() override { return true; }
};
I built test.exe, and found it depends on a.DLL because of external symbol public: __cdecl IWorker::IWorker(void) __ptr64
I know that IWorker has a compiler-generated constructor because of the vtbl, but could it be inline so we can get rid of a.DLL?
Thanks!
As #hans-passant mentioned, yes, once I removed the definition of virtual methods, problem resolved.
// a.h
struct IWorker
{
virtual bool foo() = 0;
};
But in existing project, some so-called interface class has similar dummy body and hard to refactor them.
So I really want to find the ideal solution to force-inline the c'tor, if has. Maybe not today, hope it could be impl-ed in the future.
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!
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
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.