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 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
{
};
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.