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++.
Related
There are similar questions here but they don't quite answer my question:
When to use __declspec(dllexport) in C++
Why do I need __declspec(dllexport) to make some functions accessible from ctypes?
When I cross-compile a DLL from Mac OS X using MinGW and wclang, why does my DLL work fine without using __declspec?
The MinGW DLL sample docs, and every reference I see to doing this, say to use __declspec(dllexport) before function declarations. Yet none of the code in my 9,000-line library uses it, and the DLL works great!
For example, here's a contrived example library built in the same way:
#include <stdio.h>
extern "C" {
int hello(const char* name) {
printf("Hello, %s!\n", name);
return 0;
}
}
Compiled with this on Mac OS X 10.10.3:
w32-clang++ test.cpp -shared -o test.dll
Produces a fine-looking DLL:
And my Windows application:
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
typedef int(*hellofn)(const char*);
int _tmain(int argc, _TCHAR* argv[])
{
DWORD err;
HINSTANCE dll = LoadLibrary(L"E:\\test.dll");
if (!dll) {
err = GetLastError();
std::cout << "Can't load library: " << err << std::endl;
return 1;
}
hellofn hello = (hellofn)GetProcAddress(dll, "hello");
if (!hello) {
err = GetLastError();
std::cout << "Could not load the function: " << err << std::endl;
return 2;
}
int ret = hello("nerd");
std::cout << "hello() returned " << ret << std::endl;
return 0;
}
Works great:
Am I shooting myself in the foot somehow, or is there some magic that I'm not seeing? I'm thinking that wclang (MinGW+clang) knows to use __stdcall automatically somehow and doesn't mangle the function names?
No, you do not need __declspec(dllexport), when building a DLL with MinGW; (in fact, I frequently omit it myself). The caveat is that, if just one symbol to be included in the DLL is so decorated, then all others you wish to have exported must be likewise decorated, (unless you pass the --export-all-symbols option to the linker when you build the DLL).
If you include only undecorated symbols, then all global symbols will be exported, just as if --export-all-symbols were specified by default.
However, this has nothing whatsoever to do with __stdcall vs. __cdecl calling conventions, or name mangling; it is solely a determinant of the visibility of symbols in the DLL's export table. If you don't declare your functions to be __stdcall or __cdecl, then they will be __cdecl by default; that's no problem, provided both providing DLL and caller agree on that convention. Similarly, if both agree on any name mangling convention, (which normally means that, in the case of C++ in particular, they both used the same compiler at build time), then there will be no linking problems.
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.
I have a dll and I even have the header files for the dll, but I don't have the implementation neither the lib file for the dll. I try to load up the dll with the QLibrary class and get class instance from it. I successfully retrieved the class after 2hours, but when I try to call a function on the object I get unresolved external symbol which tells me that the dll did not exported properly. For simplicity I re-created the issue with the following sources:
DLL-Project (testlibrary_global.hpp):
#ifndef TESTLIBRARY_GLOBAL_HPP
#define TESTLIBRARY_GLOBAL_HPP
#include <QtCore/qglobal.h>
#if defined(TESTLIBRARY_LIBRARY)
# define TESTLIBRARYSHARED_EXPORT Q_DECL_EXPORT
#else
# define TESTLIBRARYSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // TESTLIBRARY_GLOBAL_HPP
DLL-Project (testlibrary.hpp):
#ifndef TESTLIBRARY_HPP
#define TESTLIBRARY_HPP
#include "testlibrary_global.hpp"
#include <QDebug>
class TESTLIBRARYSHARED_EXPORT TestLibrary {
public:
TestLibrary();
~TestLibrary();
void Test();
};
extern "C" TESTLIBRARYSHARED_EXPORT TestLibrary* getInstance();
#endif // TESTLIBRARY_HPP
DLL-Project (testlibrary.cpp):
#include "testlibrary.hpp"
TestLibrary::TestLibrary() {
qDebug() << "Constructor called!";
}
TestLibrary::~TestLibrary() {
qDebug() << "Destructor called!";
}
void Test() {
qDebug() << "Hello from library!";
}
TestLibrary *getInstance() {
return new TestLibrary();
}
This is very straight forward, does not contain anything fancy really. As you can see I kept the class default as the QtCreator does did not change anything, except added another function with extern "C" and the export defined in global. the purpose of this would be to get an object from the dll itself, (since I have the .h and .dll nothing else). Now for the loader application, again dirty yet simple basic stuff:
#include <QCoreApplication>
#include <QLibrary>
#include <QDebug>
#include "testlibrary.hpp"
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QString libPath = QString("C:/Users/johorvat/Documents/QTProjects/build-TestLibrary-Desktop_Qt_5_2_0_MSVC2010_32bit_OpenGL-Debug/debug/TestLibrary.dll");
QLibrary lib(libPath);
bool loaded = lib.load();
QString error = lib.errorString();
qDebug() << "Loaded: " << loaded;
typedef TestLibrary* (*Prototype)();
Prototype Func = (Prototype) lib.resolve("getInstance");
if (Func) {
TestLibrary* tl = Func();
if (tl) {
qDebug() << "Yey, I gotta clazz!";
}
}
return a.exec();
}
I added the header file to the project because i have it anyway. I used QLibrary to load up the dll and retrieved the getInstance method from it with which I could get an instance of the TestLibrary class. However if I try to call the Test() method of TestLibrary within the if(tl) { ... } i get an unresolved external symbol error message that tells me it can't find the definition of the Test method.
What am I missing in here?
P.S.: I won't get lib files so let's focus on the problem with the dll loading :).
Regards,
Joey
Well since you've written void Test() { in your .cpp file and not void TestLibrary::Test { your function isn't being defined and so it isn't exported at all.
EDIT:
After this code like that works fine and prints "Hello" in qDebug (dll should be compiled in debug, I failed on that the first time)
QFunctionPointer raw = lib.resolve("?Test#TestLibrary##QEAAXXZ");
TestPrototype testFunc;
*(QFunctionPointer*) &testFunc = raw;
(tl->*testFunc) ();
Decorated function name is not very nice but I don't know what exactly can be done about it :) And also you'll get differently mangled names with different compilers so using Qt in this case will not be cross-platform anyway.
I have a DLL with the /clr option ON. I have the following declaration in my DLL:
int __declspec(dllexport) __cdecl test();
Also, I have a console with /clr option ON. And have the following declaration on my main.cpp file:
int __declspec(dllimport) __cdecl test();
I added the Reference to the DLL project on the property settings of my console application. But I still get unresolved externals from the compiler about the test function.
I managed to compile by manually adding a reference to the lib file generated by the compiler. But then I can't hit breakpoints inside the DLL functions (it says the source code is different from the original version or the symbols have not been loaded...)
Can someone help me?
If your DLL doesn't use any managed functionality, simply remove the /clr option from that project and recompile. If you still get the errors, it's probably related to the references in the console application.
If the DLL use managed functionality, what you need is instead like so:
DLL:
#include "stdafx.h"
namespace Test1
{
public ref class Test2
{
public:
static int test()
{
return 1;
}
};
}
Console app:
#include <iostream>
int main(int argc, char* argv[])
{
int i = Test1::Test2::test();
std::cout << i << std::endl;
return 0;
}
I am working on a plugin system in C++ whereby a C++ executable loads a dll and runs plugin_start(someclass&) via GetProcAddress.
I fully understand how to pass function pointers to the dll, and visa versa, and how the dll may use anything defined in a header file, but I would like the dll to be able to use someclass where someclass is declared in someclass.h BUT DEFINED in someclass.cpp.
The catch is, someclass is compiled into the calling executable which means when the dll tries to call a function it gets a linker error. I even understand why this is, what I don't understand is how to achieve what I want.
I imagine I can pass a pointer to the object, and a pointer to the function ie someclass* somefunction* and then call it as someclass->*somefunction() but this means I would have to pass a pointer to every function in every class.
Is there an easier way to do this, or should I stick to C-style functions and function pointers alone and forget trying to pass entire classes between the two?
Thanks,
Ben
#ifndef EVENTREGISTRAR_H
#define EVENTREGISTRAR_H
#include <vector>
typedef void (__stdcall *error_callback_t)(const char *error);
class EventRegistrar
{
public:
void OnError(error_callback_t fn);
void FireError(const char *error);
private:
std::vector<error_callback_t> errors;
};
#endif
-- Cpp
#include "PluginLoader.h"
void EventRegistrar::OnError(error_callback_t fn)
{
this->errors.push_back(fn);
}
void EventRegistrar::FireError(const char *error)
{
for (std::vector<error_callback_t>::iterator it = this->errors.begin();
it != this->errors.end(); ++it)
{
(*it)(error);
}
}
-- DLL
#include "../plugin.h"
#include <stdio.h>
void __stdcall error(const char *error) { printf("Error: %s\n",error); }
extern "C" int __stdcall plugin_start(plugin_start_data& data)
{
error_callback_t fn = error;
data.events.OnError(fn);
return LOAD_SUCCESS;
}
--Error
Error 1 error LNK2001: unresolved external symbol "public: void __thiscall EventRegistrar::OnError(void (__stdcall*)(char const *))" (?OnError#EventRegistrar##QAEXP6GXPBD#Z#Z) D:\Files\C++ Workspace\BLib\BLib\Example Plugin\main.obj Example Plugin
I did something like this a long time ago. I simply used a straight C interface to keep things simple.
There may be a better way but I think passing a pointer to the object is your best and most straight-forward approach.