How to dlsym load QString Function - c++

I'm trying to write a C++ tool using Qt for linux system. my tool using shared lib
I'm writing a lib to push data to database. method like that in header file
QString pushdata(QVariantMap params);
this fucion put in lib call libpushdata.so. I would like to load dynamic lib.so I'm using dlfcn.h and method like that:
void *handle;
QString (*pushdata)(QVariantMap*);
handle = dlopen("libpushdata.so", RTLD_LAZY);
if (!handle) {
fputs(dlerror(), stderr);
exit(1);
}
pushdata=dlsym(handle,"pushdata");
when build program I get error:
invalid conversion from ‘void*’ to ‘QString ()(QVariantMap)
I search google to how to use dynamic load library and get the instruction like that here
and here anyone can show me how to load my method QString pushdata(QVariantMap params) in shared lib. I'm using Eclipse and Centos 6.5, Qt4.8

You can use QLibrary to call functions dynamically. The following example calls a function from a shared library at runtime:
#include <QLibrary>
#include <QDebug>
typedef QString (*call_func)(QVariantMap* arg1);
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QLibrary library( "dynamic_library" );
library.load();
if( !library.isLoaded() )
{
qDebug() << "Cannot load library.";
return 0;
}
call_func func = (call_func)library.resolve( "pushdata" );
if(func)
{
func(variantMap);
}
return a.exec();
}

You can use Qt plugin machinery, as answered by Nejat.
If you insist on using just dlopen(3) and dlsym take care about:
passing a full filepath of the shared library (e.g. dlopen("./foo.so", RTLD_NOW) not only dlopen("foo.so" ...) ...) and always test the success of dlopen
beware of name mangling so declare the dlsym-ed function as extern "C" in your plugin
casting explicitly the resulting pointer:
typedef QString pushdata_sig_t(QVariantMap*);
pushdata_sig_t* pushdata
= reinterpret_cast<pushdata_sig_t*>(dlsym(handle,"pushdata"));
if (!pushdata)
{ std::cerr << "dlsym failed:" << dlerror ()
<< std::endl;
exit(EXIT_FAILURE); }
Read at least the C++ dlopen mini howto

Related

Dealing with Class Ambiguity without changing the library code

I have a C++ code that links two shared libraries (let's say, foo1.so and foo2.so). In both libraries I have a class called "Mesh", and the compiler cannot know which one I am trying to use when I try to instantiate the class Mesh (obviously I know which one I want to instantiate). I get the "error: reference to ‘Mesh’ is ambiguous"
Of course I could alter the source code of one of the libraries, wrapping the Mesh class around a namespace and that would solve the problem. I would like to avoid changing the library's code, though. Is there a way to remove this ambiguity in the source file which uses the libraries?
Thank you,
Rafael.
By using dynamic libs (.so in linux), you can load each one and use each handle to differentiate call.
See Dynamically Loaded (DL) Libraries
For example :
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
class Meshib
{
void * _handle;
double (*_cosine)(double);
public:
Meshib( const char * libraryPath)
{
char *error;
_handle = dlopen (libraryPath, RTLD_LAZY);
if (!_handle) {
fputs (dlerror(), stderr);
exit(1);
}
_cosine = reinterpret_cast<decltype(_cosine)>( dlsym(_handle, "cosine") );
if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(1);
}
}
~Meshib() {
dlclose(_handle);
}
double cosine(double v) { return (*_cosine)(v); }
};
int main(int argc, char **argv)
{
Meshib meshLib1( "foo1.so" );
Meshib meshLib2( "foo2.so" );
printf("%f\n", meshLib1.cosine(2.0));
printf("%f\n", meshLib2.cosine(2.0));
}
See this article for C++ class dynamic load.

Can function loaded from dlopen call a function from the executable that loaded it?

Setup
Suppose I wrote a program in C/C++ and wanted to allow plugin loading. The typical solution would be to write the plugin as:
plugin.c
int my_plugin_fn() {
return 7;
}
And compile it using something like gcc -fpic -shared -o plugin.so plugin.c
Then, in the main program that loads this plugin, we might have:
loader.c
#include <stdio.h>
#include <dlfcn.h>
int main() {
void *plugin_handle = dlopen("./plugin.so", RTLD_LAZY);
if (!plugin_handle) {
printf("Could not open shared object: %s\n", dlerror());
return -1;
}
int (*fn)() = dlsym(plugin_handle, "my_plugin_fn");
char *err = dlerror();
if (err) {
printf("Could not resolve symbol: %s\n", err);
return -1;
}
printf("Plugin object returned: %d\n", fn());
return 0;
}
I compiled loader.c with gcc -o loader loader.c -ldl, and after running it, the output was Plugin object returned: 7, as expected.
Question
Suppose we want to add functions in our main program (loader.c) that plugins can use. For example,
loader_v2.c
#include <stdio.h>
#include <dlfcn.h>
int times_2(int x) {
return 2*x;
}
int main() {
void *plugin_handle = dlopen("./plugin_v2.so", RTLD_LAZY);
if (!plugin_handle) {
printf("Could not open shared object: %s\n", dlerror());
return -1;
}
int (*fn)() = dlsym(plugin_handle, "my_plugin_fn");
char *err = dlerror();
if (err) {
printf("Could not resolve symbol: %s\n", err);
return -1;
}
printf("Plugin object returned: %d\n", fn());
return 0;
}
plugin_v2.c
extern int times_2(int);
int my_plugin_fn() {
return times_2(7);
}
Compiling and running these files in the same way as before produces Could not open shared object: ./loader_v2: symbol lookup error: ./plugin_v2.so: undefined symbol: times_2.
Is there a way to have plugins loaded using dlopen() call functions from the program that loaded them?
Is there a way to have plugins loaded using dlopen() call functions from the program that loaded them?
Yes, but the function that you want to call from the main executable must be exported from it, which does not happen by default. You can see which symbols are exported from your main binary with nm -D loader.
You can export all functions defined in the main executable by linking it with the -rdynamic flag.
Some linkers, most notably newer versions of GNU-ld, GOLD and LLD, support the --export-dynamic-symbol flag, which allows one to selectively export just the symbol(s) you need.
In your case, you would link your loader executable with -Wl,--export-dynamic-symbol=times_2.
The best way to do something like this is with a function pointer. You would pass the function pointer into the library function, which would subsequently call it.
So the library function would look like this:
int my_plugin_fn(int (*cb)(int)) {
return cb(7);
}
The call to dlsym would then look like this:
int (*fn)(int (*)(int)) = dlsym(plugin_handle, "my_plugin_fn");
And you would call the library function like this:
printf("Plugin object returned: %d\n", fn(times_2));

Implicitly loaded library isn't unloaded at program termination when loading wintab32.dll and calling WTInfoW

Original Post
I have a Qt application. This application needs to call some function in a dynamic library that is loaded implicitly. In the dynamic library, there is one global variable that is created when the dll is loaded and destroyed when it is unloaded.
Here's the code:
#include <QApplication>
#include <base/BASE_TEST.h>
int main(int qargc, char** qargv)
{
QApplication application(qargc, qargv);
BASE_TEST::myDLLFunction(); // call to a function in an implicitly loaded dynamic library.
return 0;
}
Implementation of myDLLFunction and of the private class of the global object.
#include <base/BASE_TEST.h>
#include <stdio.h>
class MyTest
{
public:
MyTest() { printf("------------------------------\nTEST BEGIN\n------------------------------\n"); }
~MyTest() { printf("------------------------------\nTEST END\n------------------------------\n"); }
};
MyTest test; // created at the library's loading
void BASE_TEST::myDLLFunction()
{
printf("Call from dynamic library\n");
}
If I run the application, here's what being printed in the command prompt:
------------------------------
TEST BEGIN
------------------------------
Call from dynamic library
------------------------------
TEST END
------------------------------
Up to here all is well. However, if I retrieve some information about the number of screens using QApplication::desktop(), the global object of the dynamic library isn't destroyed.
int main(int qargc, char** qargv)
{
QApplication application(qargc, qargv);
QDesktopWidget* desktop = QApplication::desktop(); // This call prevent the global objects to be destroyed.
BASE_TEST::myDLLFunction(); // call to a function in an implicitly loaded dynamic library.
return 0;
}
Here's what is printed in the command prompt:
------------------------------
TEST BEGIN
------------------------------
Call from dynamic library
The main function still returns normally and no exception is thrown.
I looked at the code of QApplication and QDesktopWidget and the QDesktopWidget destructor is being called at the end of the main function's scope and QDesktopWidgetPrivate::cleanup() is called.
I'm on Windows, using Qt 4.8.6.
Does someone has any idea?
Thanks! :)
Edit
As mentionned in the answer below, the problem seems to be linked to loading wintab32.dll which will load the Wacom driver's dynamic library if installed.
I finally found the source of the issue:
Calling QApplication::desktop() made Wacom_Tablet.dll be loaded. By uninstalling the Wacom driver, the problem went away.
I was able to reduce the sample program to:
#include "../baseTest/BASE_TEST.h"
#include <wtypes.h>
#include "wintab.h"
typedef UINT(WINAPI *PtrWTInfo)(UINT, UINT, LPVOID);
static PtrWTInfo ptrWTInfo = 0;
int main(int /*qargc*/, char** /*qargv*/)
{
BASE_TEST::myDLLFunction(); // call to a function in an implicitly loaded dynamic library.
HMODULE hWintab = LoadLibrary(L"wintab32.dll");
PtrWTInfo pWTInfo = (PtrWTInfo)GetProcAddress(hWintab, "WTInfoW");
WORD thisVersion;
pWTInfo(WTI_INTERFACE, IFC_SPECVERSION, &thisVersion);
if (hWintab)
FreeLibrary(hWintab);
return 0;
}
and still be able to reproduce the issue.
I've contacted Wacom about it and am waiting their reply.

QLibrary Visual C++ global variables

I use a Visual C++ DLL within a Qt project using QLibrary. Everyhing works fine for the functions, but can I also directly access global variables that are exported by the DLL? My program crashes if I try to do that, however, the resolving seems to work.
The global variables are exported just as the functions that work, with extern "C" and extern __declspec (dllexport). Is this even possible, or do I need to write a function to return the variable first? If it is possible, could you provide an example like it is done for functions in the Qt assistant?
You can define a function to access a global variable. The code for the shared library can be as follows :
int myVariable;
extern "C" Q_DECL_EXPORT int get_myVariable()
{
return myVariable;
}
In your Qt application you can call the function and access the variable :
#include <QLibrary>
typedef int (*get_myVariable_func)();
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QLibrary library( "./dynamic_library" );
library.load();
if( !library.isLoaded() )
{
qDebug() << "Cannot load library.";
return 0;
}
get_myVariable_func get_variable = (get_myVariable_func)library.resolve( "get_myVariable" );
if( get_variable )
{
int var= get_variable();
qDebug() << "my variable = " << var;
}
return a.exec();
}

Access class members from DLL (NOT LIB!!!)

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.