I would like to understand the DLL mechanism and what the compiler does when I loads the DLL at run-time (i.e. I will not use the generated .lib).
Consider the following C++ code:
DLL interface header file
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
class MYDLL_API Base
{
public:
Base();
virtual ~Base();
virtual int get_number() const;
virtual const char* what() const = 0;
private:
int i_;
};
class MYDLL_API Child : public Base
{
public:
Child();
virtual ~Child();
virtual int get_number() const override;
virtual const char* what() const override;
private:
int j_;
};
extern "C" {
MYDLL_API Base* __cdecl initializeObject();
}
DLL implementation source file
#include "MyDLL.hh"
Base::Base()
: i_(42)
{}
Base::~Base()
{}
int Base::get_number() const
{
return i_;
}
Child::Child()
: Base()
, j_(24)
{}
Child::~Child()
{}
int Child::get_number() const
{
return j_;
}
const char* Child::what() const
{
return "Hello!";
}
Base* initializeObject()
{
return new Child();
}
The goal of this DLL is to have a common interface defined by the Base class, but it allows specifics implementations compiled in different DLLs that are loaded at runtime (here the Child class is exposed for the purpose of the example).
At this stage, if I naively include the DLL's header:
#include "MyDLL.hh"
int main()
{
Base* b = new Child();
std::cout << b->get_number() << std::endl;
std::cout << b->what() << std::endl;
delete b;
getchar();
return 0;
}
The linker complains LNK2019 and LNK2001 errors: it can not resolves symbols. So, it behaves as expected (I did not use the .lib).
Consider now, the following code that I use to load the DLL at runtime:
#include "MyDLL.hh"
typedef Base* (*initFuncType)();
int main()
{
HINSTANCE handle = LoadLibrary(L"MyDLL.dll");
initFuncType init = nullptr;
init = (initFuncType)(GetProcAddress(handle, "initializeObject"));
if (init)
{
Base* b = init(); //< Use init() !
std::cout << b->get_number() << std::endl;
std::cout << b->what() << std::endl;
delete b;
}
getchar();
FreeLibrary(handle);
return 0;
}
This time it works, the linkage is done.
1st question: What happened? What changed for the compiler and the linker? The use of the function pointer on initializeObject() solves the problem.
The other issue I do not understand well is when I remove virtual and override of get_number():
int get_number() const;
I have a LNK2019 error because of the unresolved Base::get_number(void) const symbol in the _main function. I understand that the virtual keyword will resolve the member function dynamically (at run-time). In our case, the DLL is not loaded yet, the get_number symbol is not available.
2nd question: Does this means that methods must always be virtual using DLL run-time linking?
3rd question: How can I have the C++ function exportation with the Windows API? So that I could remove the extern "C" { ... } stuff.
Thanks for your reading! I hope I will read interesting answers! :)
There are two ways to link dll files.
The 2nd way (the way it works) is the C Binding approach, where you query the dll for a specific function name and it returns a functor to you.
Using the 2nd way you won't be able to extend the base classes, since they are not defined (you don't have any code to be copy pasted so to speak at linkage time).
In order to have a dll who's classes can be extended, you will need to use dynamic binding. You need to compile your .dll and also provide a Symbols Library (or an export library). You have this option in VS studio in project properties.
The mechanism is as following :
Compile Dll project -> output : myLib.dll , myLib.lib
Use exported symbols from myLib.lib inside your main project (main project takes myLib.lib as dependency)
at runtime,due to the binding, your program will know it requires myLib.dll to work so it will load it (if found, else you get runtime error)
Another advantage of using Export Library is that you can export C++ functions (which are mangled on export).
It's very hard to have C Binding on mangled functions.
C Binding on the otherhand, compared to the dynamic binding, won't make your program scream if myLib.dll isn't found , you will just get a null pointer to function.
Related
I have a confusing issue using a static member variable as a default parameter. Since the same language construct works in a different place, it might be related to project (DLL) inter-dependencies. So please accept my apologies if my example is too complex, but I should draw the whole picture since I do not have any idea what is wrong.
I have a base class (representing kind of an error code)
ErrorBase.h
class ErrorBase
{
public:
typedef unsigned long ErrorCode;
/// here go the error codes. For reasons I do not want to explain, I cannot use an enumeration here.
static const ErrorCode ERROR_UNINITIALIZED;
static const ErrorCode ERROR_OK;
///...and so on
ErrorBase(ErrorCode theCode = ERROR_UNINITIALIZED);
};
...and in ErrorBase.cpp, I am assigning values to the codes...
const ErrorBase::ErrorCode ErrorBase::ERROR_UNINITIALIZED = 0xffffffff;
const ErrorBase::ErrorCode ErrorBase::ERROR_OK = 0x0;
//.. and so on...
ErrorBase is exported from a DLL which provides some general purpose classes to our project
Now I am deriving another error class for more specific errors which has additional attributes specific for the particular type of error. The class SpecificError is part of a different DLL which links to the general purpose DLL containing ErrorBase. I have not included the dllimport/dllexport shebang, but we are using this all over the place and it works in all cases. If you have doubts, I can edit my code example.
SpecificError.h
class SpecificError : public ErrorBase
{
public:
static const ErrorCode SPECIFIC_ERROR_UNINITIALIZED;
static const ErrorCode SPECIFIC_ERROR_SOMETHING_WENT_WRONG;
SpecificError(ErrorCode theCode = SPECIFIC_ERROR_UNINITIALIZED);
};
... and in the SpecificError.cpp I am defining these values:
const SpecificError::ErrorCode SpecificError::SPECIFIC_ERROR_UNINITIALIZED = ErrorBase::ERROR_UNINITIALIZED;
Like ErrorBase, SpecificError is exported from the DLL handling specific functionality. Note that both error classes declare a constructor using the "UNINITIALIZED" value as a default for the error code.
Now I have a program being dependent on both DLLs, thus linking to both of them through the corresponding import libraries. This program includes ErrorBase.h and SpecificError.h. It does not seem to have any problems with ErrorCode.h, but about SpecificError.h I am receiving an
LNK2001 unresolved external symbol SpecificError::ErrorCode SpecificError::SPECIFIC_ERROR_UNINITIALIZED referenced in main.obj.
(remark: main.cpp does not explicitly use SpecificError, it just includes the header file).
I was able to work-around the problem by removing the default parameter from the SpecificError constructor and declaring a default constructor which in its implementation calls the inherited constructor of ErrorBase passing SPECIFIC_ERROR_UNINITIALIZED to it. This leads me to the assumption that the symbol SPECIFIC_ERROR_UNINITIALIZED is properly declared and defined but cannot be used as a parameter default. However, this seems to apply to SpecificError only, everything seems fine in ErrorBase.
Toolset: I am using Visual C++ 2017 as a compiler.
I recreated the linked error. Make the following changes to your files and it should work just fine based on the code snippets that you showed above:
SpecificError.cpp
// I sent theCode to the Base class
SpecificError::SpecificError(ErrorCode theCode) : ErrorBase(theCode)
{
// ...
}
In ErrorBase.cpp I just added the constructor but you probably already have this:
ErrorBase::ErrorBase(ErrorCode theCode)
{
// ...
}
After I did this, I had to also move the initializations of the static consts to the .h from the .cpp files. Then I tested the code by doing:
SpecificError e; // theCode ends up being 0xffffffff
SpecificError e1(20); // theCode ends up being 20
I hope that this helps you.
Here is what my ErrorBase.cpp looks like:
#pragma once
#include"ErrorBase.h"
#include<iostream>
ErrorBase::ErrorBase(ErrorCode theCode) {
std::cout << theCode << std::endl;
}
ErrorBase.h:
#pragma once
class ErrorBase
{
public:
typedef unsigned long ErrorCode;
static const ErrorCode ERROR_UNINITIALIZED = 0xffffffff;
static const ErrorCode ERROR_OK = 0x0;
ErrorBase(const ErrorCode = ERROR_UNINITIALIZED);
};
SpecificError.cpp:
#pragma once
#include"SpecificError.h"
SpecificError::SpecificError(ErrorCode theCode) : ErrorBase(theCode)
{
}
SpecificError.h:
#pragma once
#include "ErrorBase.h"
class SpecificError : public ErrorBase
{
public:
static const ErrorCode SPECIFIC_ERROR_UNINITIALIZED = ErrorBase::ERROR_UNINITIALIZED;
static const ErrorCode SPECIFIC_ERROR_SOMETHING_WENT_WRONG = -42;
SpecificError(ErrorCode theCode = SPECIFIC_ERROR_UNINITIALIZED);
};
I tried this and it is working, the class name was missing in ErrorBase.cpp
const ErrorBase::ErrorCode ErrorBase::ERROR_UNINITIALIZED = 0xffffffff;
const ErrorBase::ErrorCode ErrorBase::ERROR_OK = 0x0;
If still not working then let me know.
You doing it wrong. The linker error means that it doesn't know where to get your constant value. You should use dynamic linkage with a first DLL. Let me show
Example of C++ class export:
C++ How to export a static class member from a dll?
And your code should be changed:
ErrorBase.h
#ifndef MAIN_DLL
#define MAIN_DLL 1 // or you can add MAIN_DLL definition to the your first project Macroses
#endif
#if MAIN_DLL
#define ERROR_API __declspec(dllexport) // export things to other modules
#else
#define ERROR_API __declspec(dllimport) // import things from the external DLL
#endif
class ERROR_API ErrorBase
{
public:
typedef unsigned long ErrorCode;
/// here go the error codes. For reasons I do not want to explain, I cannot use an enumeration here.
static const ErrorCode ERROR_UNINITIALIZED;
static const ErrorCode ERROR_OK;
///...and so on
ErrorBase(ErrorCode theCode = ERROR_UNINITIALIZED);
};
SpecificError.h
#pragma once
#define MAIN_DLL 0
#include "../Dll_stack_ovfl1/ErrorBase.h" // change it to your path
class SpecificError : public ErrorBase
{
public:
static const ErrorCode SPECIFIC_ERROR_UNINITIALIZED;
static const ErrorCode SPECIFIC_ERROR_SOMETHING_WENT_WRONG;
SpecificError(ErrorCode theCode = SPECIFIC_ERROR_UNINITIALIZED);
};
And the final step, configure the second DLL project to link it with exports of the first one:
Configuration Properties/Linker/Input/Additional dependencies
Add something like "$(SolutionDir)$(Configuration)\ErrorBase.lib"
Once again its just example, I don't know the real path of "lib" file and your project name for ErrorBase DLL - change it to your specific.
I'm crating a DLL in C++ which handles different classes: in particular I have a main class which have a lot of member objects of the other the classes. For exmaple I have my class "A" which has a member of class "B":
Class A header
#include "BClass.h"
class __declspec(dllexport) A
{
B* objectB = nullptr;
public:
A();
initClassB();
}
Class A cpp:
A::A() { // Class A constructor. In these statements B is still nullptr}
A::initCLassB() { objectB = new B() }
Class B header:
class __declspec(dllexport) B
{
int x;
bool y;
char* z;
public:
B() { // class B constructor}
}
When I import my DLL in my target project, it compiles with no error, and until here everything's ok.
My main is something like:
#include "AClass.h"
int main()
{
A a;
return 0;
}
Notice that I don't invoke initClassB() in my main and this cause the error "Unable To Read Memory". If I explore the debugger I see that the error is related to all A::objectB members.
Why is this happening? Can't the shared library handle a nullptr member object?
I'm quite new in compiling DLL and this error looks a bit weird to me
DLLs on windows need to export their symbols when building the dll. Client code that uses the library needs to import it.
In your header for class B:
class __declspec(dllexport) B
This is what you want when building the library, but in code that uses it, you want it to be dllimport instead. Usually people use macros to toggle this, with it defaulting to import, and only exporting if a special commandline macro is set.
See this Macro for dllexport/dllimport switch
I am working in Visual Studio C++.
I made an class with a non-static function and packaged it as a dll. Here is the code to generate my dll:
// head file
#ifndef FUNCTIONS_H_
#define FUNCTIONS_H_
#include <string>
#include <memory>
#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport)
#else
#define MATHFUNCSDLL_API __declspec(dllimport)
#endif
MATHFUNCSDLL_API class Functions
{
public:
MATHFUNCSDLL_API void func(int, std::string);
};
extern "C" MATHFUNCSDLL_API Functions * __cdecl create_class();
#endif
// cpp file
#include "stdafx.h"
#include "Functions.h"
#include <iostream>
void Functions::func(int id, std::string name)
{
std::cout << "Your ID: " << id << ". Your name: " << name << std::endl;
}
Functions * create_class()
{
std::cout << __FUNCTION__ << std::endl;
return new Functions();
}
Now I have a C++ project that loads this dll dynamically. Here is the code:
#include <iostream>
#include <Windows.h>
#include "../../testDmcDLL/testDmcDLL/Functions.h"
typedef Functions *(__stdcall *f_funci)();
int main(int argc, char ** argv)
{
HINSTANCE hGetProcIDDLL = LoadLibrary("C:\\Documents\\Visual Studio 2013\\Projects\\testDmcDLL\\Debug\\testDmcDLL.dll");
f_funci func_create_class = (f_funci)GetProcAddress(hGetProcIDDLL, "create_class");
Functions * pf = func_create_class();
////LNK error////pf->func(1, "toto");
system("pause");
return 0;
}
I can make sure that hGetProcIDDLL and func_create_class have been initialized successfully (I've tested them with if, but here I removed the if).
When I run this project, I can see that create_class is shown on the console because there is std::cout << __FUNCTION__ << std::endl; in that function. So everything looks fine.
However, when I compile it with the code pf->func(1, "toto") uncommented, I get a linker (LNK2019) error:
Error 1 error LNK2019: unresolved external symbol
"__declspec(dllimport) public: void __thiscall
Functions::func(int,class std::basic_string,class std::allocator >)"
(__imp_?func#Functions##QAEXHV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z)
referenced in function _main c:\documents\visual studio
2013\Projects\testLoadDmcDLL\testLoadDmcDLL\main.obj testLoadDmcDLL
The class definition is not quite right with the exports, it should be of the form;
class MATHFUNCSDLL_API Functions // MATHFUNCSDLL_API moved
{
public:
void func(int, std::string); // MATHFUNCSDLL_API removed
};
Once a class is exported, all its members are exported.
You don't mention how MATHFUNCSDLL_EXPORTS is defined during compilation (from the command line or possibly in the stdafx.h), but make sure it is defined when building the dll, but not when building the exe. Be sure to link against the .lib produced with the .dll.
Notes on the LoadLibrary and GetProcAddress usage; if you require the dll to be loaded dynamically, you need to get the C++ class member function bound to the exported function. I've not seen a successful implementation of this or if it is even reasonable possible. If the use of the LoadLibrary and GetProcAddress is required, consider using an abstract class and create the object in a factory of some sort.
You don't detail the motivation for the dynamic loading of the dll, but consideration could also be given the delay loading the dll.
If the motivation is to delay the loading of the dll, but the same dll is always used, then the delay-load linking may help. If the motivation is to load an unknown dll (by name/location) based on some runtime parameter (or configuration), then the virtual base class and a single C-style function as a factory for the object is probably the preferred solution.
There is a good code project article on this describing various solutions for this. In particular using the abstract base class is very portable.
If you don't rely on the import library but call GetProcAddress, you need to do that for every function you're importing. You never called GetProcAddress for __imp_?func#Functions##QAEXHV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z (which is how your Functions::func is mangled in the DLL).
Also, be aware that you get a function pointer from GetProcAddress. While that points to the code implementing pf->func, function pointers aren't called with member function call syntax.
The root problem is that GetProcAddress really is designed for C, not C++.
I'm trying to implement a design similar to the one described here:
http://www.linuxjournal.com/article/3687
I've got a core projects which compiles into an executable binary. I also want to have shared libraries loaded at runtime using dlopen(). Now I'm facing the problem that there are some classes which should be known in the core project and also in all of the loaded libraries. I thought I'd put them together in another shared library which gets linked to all of them at compilation. Everything seems to compile fine but during loading the shared library ConnectionModule.so dlopen returns no handle and dlerror says 'undefined symbol: _ZTV17PipelineProcessor' where PipelineProcessor is a class defined and implemented in the shared library which should be compiled in every addition shared library.
Does anyone have an idea of what is wrong with my implementation or is this design just doomed to fail?
some code here:
loading of library at runtime
#include "../SharedHeaders/SharedInEveryLibrary.h"
// ...
map<string, maker_t*, less<string> > module_library;
// ...
void *hndl = dlopen(library_file_path, RTLD_NOW | RTLD_GLOBAL);
if (hndl == nullptr) {
Logger::error << "Could not load library " << library_file_name << ": " << dlerror() << endl;
exit(-1);
}
ConditionModule.h (should be loaded at runtime)
#pragma once
#include "../SharedHeaders/SharedInEveryLibrary.h"
class ConditionModule : public B {
public:
A* processRequest(X* data) override; // implemented at ConditionModule.cpp
};
extern "C" {
A *maker() {
return new ConditionModule;
}
class proxy {
public:
proxy() {
module_library["condition_module"] = maker;
}
};
proxy p;
}
... and of course aome of the content of SharedInEveryLibrary.h
class Z; // gets implemented later, I guess it's not important
struct X {
int something;
// ...
};
class A {
public:
virtual void setSomeData(X* v_some_data);
virtual A* process(Z* data) = 0;
protected:
X* some_data;
};
class B : public A {
public:
A* process(Z* data) override;
virtual A* processRequest(X* data) = 0;
};
typedef A* maker_t();
extern map<string, maker_t*, less<string> > module_library;
EDIT -----
Forgot to mention that I currently develop only with Linux as compilation target.
There is nothing wrong with this design. But when you dlopen() a shared library, all it's symbols need to be resolved. Your error means that you do not have the path to .so your library depends on in LD_LIBRARY_PATH. To check what library it needs, use
ldd <your library.so>
Than add the directory where this library resides to LD_LIBRARY_PATH.
I have a QT library and I want to import it in another project.
Now, since I want that, even when I modify the library, the other project does not need to be compiled again, I started using QLibrary.
But... I can't import a class. Or better, I can import the class, but I can't access its methods.
This is the example I made.
This is the class declaration:
class TESTDLL_LIBSHARED_EXPORT TestDLL_lib
{
public:
TestDLL_lib();
int a;
int b;
int c;
int getValues();
};
and this the implementation:
#include "testdll_lib.h"
TestDLL_lib::TestDLL_lib()
{
a = 10;
b = 20;
c = 30;
}
int TestDLL_lib::getValues()
{
return a+b+c;
}
extern "C" TESTDLL_LIBSHARED_EXPORT TestDLL_lib* create_TestDLL_lib()
{
return new TestDLL_lib();
}
while this is the main file, in the other project:
#include <testdll_lib.h>
#include <QDebug>
#include <QLibrary>
int main(int argc, char *argv[])
{
QLibrary library("TestDLL_lib");
if (library.load())
{
typedef TestDLL_lib* (*create_TestDLL_lib_fun)();
create_TestDLL_lib_fun create_TestDLL_lib = (create_TestDLL_lib_fun)library.resolve("create_TestDLL_lib");
if (create_TestDLL_lib)
{
TestDLL_lib *myClassInstance = create_TestDLL_lib();
if (myClassInstance)
{
//qDebug() << QString::number(myClassInstance->getValues());
qDebug() << QString::number(myClassInstance->a) + " " + QString::number(myClassInstance->b) + " " + QString::number(myClassInstance->c);
}
}
library.unload();
}
}
Now, I can access all the data values (a, b, c) of the object myClassInstance (and, if i change them in the DLL, they also get changed in the program without a rebuild) but I can't call myClassInstance->getValues() because I get
main.obj:-1: error: LNK2001: unresolved external symbol "__declspec(dllimport) public: int __thiscall TestDLL_lib::getValues(void)" (__imp_?getValues#TestDLL_lib##QAEHXZ)
How can I solve this? Is it possible to call methods from imported classes?
Thank you..
You cannot call methods on classes imported at runtime. This is because the compiler links these calls at compile-time and not at run-time (which it cannot do). A way out is provided by our good ol' friend, the vtable:
You can, call virtual methods on classes implementing an interface (the interface is not "imported" at runtime). That means to define a class defining the interface using virtual (possibly pure virtual) methods. TestDLL_lib would then inherit that interface, implementing the methods. You would refer to the TestDLL_lib instance via that interface and call methods trough that interface, effectively calling them trough the vtable of the interface, which is "superseded" by TestDLL_libs vtable.
Don't forget to make your d'tor virtual and to add a virtual dtor to the interface. If you don't do that you cannot safely delete instance trough the interface pointer.
I might also explain why you can access members, but not call functions on "imported" classes. The members are accessed by memory location, and the memory location is solely defined by the compiler. Thus the compiler generates the code to access members without ever referring to any of the classes' symbols (methods and so on). This in turns leads to no linkage dependency. Note however that you would need to recompile both the DLL and the application using the DLL if you change the class, e.g. adding or removing a member, since that changes the memory layout.
class TestInterface
{
public:
virtual ~TestInterface()
{
}
virtual int getValues() = 0;
}
class TESTDLL_LIBSHARED_EXPORT TestDLL_lib : public TestInterface
{
public:
TestDLL_lib();
virtual ~TestDLL_lib();
int a;
int b;
int c;
int getValues() override; // MSVC may not support "override"
};
// return pointer to interface!
// TestDLL_lib can and should be completely hidden from the application
extern "C" TESTDLL_LIBSHARED_EXPORT TestInterface *create_TestDLL_lib()
{
return new TestDLL_lib();
}