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();
}
Related
I'm writing a cross-platform application and need to pass across argc and argv from Objective-C in Xcode to my generic argument handler class in C++. I have a global pointer to this handler class which I set with a new command, but because I can't do new in Objective-C I'm trying the following:
I have a header file called MacCommandLineArgs.h which contains only the following:
static int cmdlArgc = 0;
static const char** cmdlArgv = NULL;
I then set these from within main.m:
int main(int argc, char *argv[])
{
cmdlArgc = argc;
cmdlArgv = (const char**)argv;
return NSApplicationMain(argc, (const char **)argv);
}
Once the Objective-C++ section of the application has been entered, I try to read back these global variables in order to pass them to the pure-C++ class:
int argc = cmdlArgc;
const char** argv = cmdlArgv;
globalCommandLineArgs = new CCommandLineArgs(argc, argv);
When stepping through with the debugger, cmdlArgc and cmdlArgv show up as valid data but argc and argv are still 0 and NULL after the assignment. What am I doing wrong here?
You don't show how cmdlArgc and cmdlArgv are declared; it's surely in a header file, but what does it look like?.
Nothing outside of main.m will have access to those variables as they have been defined static, which leads me to wonder why you aren't getting linker errors. I have concluded that the declaration of the of cmdlArgc and cmdArgv is something like this:
int cmdlArgc;
const char** cmdlArgv;
rather than this:
extern int cmdlArgc;
extern const char** cmdlArgv;
So every implementation file that includes the header will get their own copy, which is why it's 0/NULL.
The solution is to drop the use of static in main.m and start using extern in the header.
However it's still an ugly pattern and I would think the very best solution is to rename main.m to main.mm and initialise CCommandLineArgs in main(), which is both clean and simple.
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
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'm implementing a simple threaded application in which I have a server thread, and a gui thread. So, the thing goes a bit like this:
int main(int argc, char *argv[]) {
appMain app(argc, argv);
return app.exec();
}
appMain::appMain(int c, char **v) : argc(c), argv(v) {
this->Configuration();
}
int appMain::exec() {
appServer Server;
try {
ServerThread = boost::thread(Server);
ServerThread.join();
} catch (...) {
return EXIT_FAILURE;
}
return 0;
}
appMain::Configuration method just picks up a configuration file and loads it into a struct appConfig. The thing is, I need this structure to be modifiable from any place it might be used, which means I've got to use a mutex so as to avoid memory corruption.
Hoping to avoid any possible pointer problems and thread argument passing (which seems kind of painful), I decided to use a global variables, which I declared in appConfig.h:
struct appConfig config;
boost::mutex configMutex;
Thus I added my extern declarations where I use them:
appMain.cpp
extern struct appConfig config;
extern boost::mutex configMutex;
appServer.cpp
extern struct appConfig config;
extern boost::mutex configMutex;
appServer::appServer() {
return;
}
void appServer::operator()() {
configMutex.lock();
cout << "appServer thread." << endl;
configMutex.unlock();
}
appServer::~appServer() {
return;
}
It seems to me that there shouldn't be any kind of problem at compile time, yet I get this nice gift:
appServer.o: In function `~appServer':
/usr/include/boost/exception/detail/exception_ptr.hpp:74: multiple definition of `configMutex'
appMain.o:/home/eax/CCITP/src/appMain.cpp:163: first defined here
appServer.o: In function `appServer':
/usr/include/boost/exception/exception.hpp:200: multiple definition of `config'
appMain.o:/usr/include/c++/4.6/bits/stl_construct.h:94: first defined here
collect2: ld returned 1 exit status
Any insight on how I could solve this will be appreciated...
Julian.
This isn't really a boost problem per se: you've declared a global variable in a header that's therefore defined in global scope in both compilation units, leading to multiple definitions.
Declaring it extern in the header, and defining it in exactly one .cpp file should work.
I'm trying to figure out why this is not working. I want to do like in Java where main is a static function in a class but this is producing unresolved external symbol error:
static class MainClass
{
public:
static int _tmain(int argc, char* argv[])
{
return 0;
}
};
Why doesn't this work?
Thanks
C++ does not work like that.
You need main as a function:
int main(int argc,char* argv[])
{
//STUFF
}
Because _tmain is mangled in the binary with the class name MainClass in it, so multiple classes could have a function _tmain in them and not conflict. It's not got the same mangled name as ::_tmain is going to have.
I remember that with an earlier version of MSVC, it accepted the following without a linker error which ended up accidentally as a result of macro expansion in my code base once
namespace bar {
int main() { }
}
It apparently treated the name main specially and didn't mangle it or mangle it the same as ::main. But such a thing is not Standard conformant. Like in the class case, such a function is completely unrelated to the main function.
_tmain is called from CRT. You need to set in your linker an entry point to another function that will call MainClass::_tmain instead.
Because, in C++, you cannot put an entry point inside a class. This answer might help.
Why doesn't that work? Because it's not C++.
struct MainClass {
static int main(int argc, char** argv) {
return 0;
}
};
int main(int argc, char** argv) {
return MainClass::main(argc, argv);
}
It's not really C++, so much as the standard linker process which is looking for an export of a specific name (with C-style linkage). The specific export varies based on the compiler and executable type, but the format is specific for each type. For example, Windows GUI exe's have different entry points than console, and specific for ASCII or UNICODE. But the linker is always looking for a function with a specific link name, which is why a static member won't work.
You always need main() defined as a global function. This is where the program always starts in C++. You could simple call your static class function from main and pass on the variables if you really want to:
class MainClass
{
public:
static int _tmain(int argc, char* argv[])
{
return 0;
}
};
int main(int argc, char* argv[]) {
return MainClass::_tmain(argc, argv);
}