I searched the entire network for an answer, but could not find a solution to my problem. Or maybe I did it, but because I start with C ++ / programming / Qt, I did not understand them. The closest question was here. Using a Qt-based DLL in a non Qt application . I tried to use this method, but so far without success.
I am trying to create a DLL, this is the API for our USB device. The library should work with applications other than Qt. I have PIMPL-ed all Qt materials and private classes, so the code below is a single layer under public classes. I use QSerialPort and a lot of SIGNAL / SLOT, so I need a QCoreApplications event loop. The ReaderSerial, where Qt stuff starts, also instantiates another class in which QSerialPort runs in another QThread.
At the moment, my problem is that all error crashes on error: "QTimer can only be used with threads running with QThread"
I think that my Qt-based classes, such as ReaderSerial, do not see the QCoreApp event loop or anything like that. So my question is how to provide a QCoreApplication event loop for my DLL so that all Qt-based classes are created and I can call methods from my DLL.
Thanks so much for the answers.
reader_p.h
class ReaderPrivate { public: ReaderPrivate(); ~ReaderPrivate(); void static qCoreAppExec(); ReaderSerial *readerSerial; void connectReader(std::string comPort); void disconnectReader(); };
reader.cpp
// Private Qt application namespace QAppPriv { static int argc = 1; static char * argv[] = {"API.app", NULL}; static QCoreApplication * pApp = NULL; }; ReaderPrivate::ReaderPrivate() { std::thread qCoreAppThread(qCoreAppExec); qCoreAppThread.detach(); readerSerial = new ReaderSerial; } ReaderPrivate::~ReaderPrivate() { delete readerSerial; } void ReaderPrivate::qCoreAppExec() { if (QCoreApplication::instance() == NULL) { QAppPriv::pApp = new QCoreApplication(QAppPriv::argc, QAppPriv::argv); QAppPriv::pApp->exec(); if (QAppPriv::pApp) delete QAppPriv::pApp; } } void ReaderPrivate::connectReader(std::string comPort) { readerSerial->openDevice(comPort); } void ReaderPrivate::disconnectReader() { readerSerial->closeDevice(); }
Based on @Kuba Ober's answer, I created a shared library. It took me a while to figure out what was going on and how to make it work, but it still doesn't do what it should. Therefore, I now ask for advice on how to make this code work.
apic.h
#include "Windows.h" extern "C" { __declspec(dllexport) void WINAPI kyleHello(); }
apic.cpp
#include "apic.h" #include "appthread.h" void WINAPI kyleHello() { worker->hello(); } BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID) { static AppThread *thread; switch (reason) { case DLL_PROCESS_ATTACH: thread = new AppThread; thread->start(); break; case DLL_PROCESS_DETACH: delete thread; break; default: break; } return TRUE; };
appthread.h
#include <QThread> #include <QCoreApplication> #include <QPointer> #include "worker.h" static QPointer<Worker> worker; class AppThread : public QThread { public: AppThread(); ~AppThread(); // No need for the Q_OBJECT QPointer<QCoreApplication> m_app; void run() Q_DECL_OVERRIDE { std::cout << "\n AppThread::run"; int argc; char *argv; QCoreApplication app(argc, &argv); m_app = &app; std::cout << "\nAppThread::run before Worker"; Worker worker_; worker = &worker_; std::cout << "\nAppThread::run before app.exec"; app.exec(); } //using QThread::wait(); // This wouldn't work here. };
appthread.cpp
#include "appthread.h" AppThread::AppThread() { std::cout << "\n AppThread::ctor"; } AppThread::~AppThread() { std::cout << "\n AppThread::dtor \n"; m_app->quit(); wait(); }
worker.h
#include <QObject>
worker.cpp
#include "worker.h" Worker::Worker() { std::cout << "\nWorker::ctor"; hello(); } void Worker::hello() { std::cout << "\nWorker::hello()";
The conclusion from this is usually:
AppThread::ctor Worker::hello() AppThread::dtor
sometimes:
AppThread::ctor Worker::hello() AppThread::run AppThread::dtor
sometimes:
AppThread::ctor Worker::hello() AppThread::dtor QMutex: destroying locked mutex
GitHub repo: https://github.com/KyleHectic/apic.git