如何在使用QtNetwork和QThread的QT DLL中正确关闭QCoreApplication ?



我试图创建一个QT DLL在InnoSetup安装程序中使用它(InnoSetup是用Delphi Pascal编写的)。

这个DLL应该有一个从InnoSetup调用时从互联网下载文件的函数。

InnoSetup调用是这样的:

procedure downloadFile();
external 'doDownload@files:testdll.dll,libssl-1_1.dll,libcrypto-1_1.dll stdcall loadwithalteredsearchpath delayload';

然后,我这样调用它:

function InitializeSetup(): Boolean;
begin
Result := True;
ExtractTemporaryFile('testdll.dll');
downloadFile();
end;

问题是下载文件();如果我需要稍后调用它(在初始调用之后),因为在第一次调用时,不知何故,我怀疑, QCoreApplication没有正确关闭并保持在执行循环中。当我第二次调用这个函数时,什么也没有发生,没有文件从互联网下载。再次下载文件的唯一方法是关闭并重新打开Inno安装程序。

下面是我的代码:

TESTDLL.pro

QT -= gui
QT += network
TEMPLATE = lib
DEFINES += TESTCLASS_LIBRARY
CONFIG += c++11 dll
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
SOURCES += 
testdll.cpp 
libsdownloadThread.cpp
HEADERS += 
testdll_global.h 
testdll.h 
libsdownloadThread.h
QMAKE_LFLAGS += -Wl,--output-def,testdll.def
# Default rules for deployment.
unix {
target.path = /usr/lib
}
!isEmpty(target.path): INSTALLS += target

TESTDLL.h

#ifndef TESTDLL_H
#define TESTDLL_H
#include <QtCore>
#include "testdll_global.h"
#include "libs/downloadThread.h"

class TestDLL : public QObject
{
Q_OBJECT
public slots:
void handleResults(const QString &);
void startWThread();
void initQCoreApp();
private:
void debugMsg(QString fileName, QString message)
{
QFile file(fileName);
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out << message;
file.close();
};
};
#endif

TESTDLL.cpp

#include "testdll.h"
namespace QCoreAppDLL
{
static int argc = 1;
static char arg0[] = "testdll.cpp";
static char * argv[] = { arg0, nullptr };
static QCoreApplication * pApp = nullptr;
}
extern "C" TESTCLASS_EXPORT void doDownload()
{
TestDLL a;
a.initQCoreApp();
}
void TestDLL::startWThread()
{
downloadThread *thread = new downloadThread(this);
connect(thread, &downloadThread::finished, thread, &QObject::deleteLater);
connect(thread, &downloadThread::resultReady, this, &TestDLL::handleResults);
thread->start();
}
void TestDLL::initQCoreApp()
{
if (!QCoreApplication::instance())
{
QCoreAppDLL::pApp = new QCoreApplication(QCoreAppDLL::argc, QCoreAppDLL::argv);
TestDLL a;
a.startWThread();
QCoreAppDLL::pApp->exec();
}
}
void TestDLL::handleResults(const QString &)
{
debugMsg("result.txt","succes!");
if (QCoreAppDLL::pApp)
QCoreAppDLL::pApp->quit();
}

DOWNLOADTHREAD.h

#ifndef downloadThread_H
#define downloadThread_H
#include <QtNetwork>
#include <QDebug>
class downloadThread : public QThread
{
Q_OBJECT
signals:
void resultReady(const QString &s);
public:
downloadThread(QObject *parent);
~downloadThread();
void run() override {
QString result;
initDownload();
emit resultReady(result);
};
void initDownload();
void doDownload(QString url);
private:
QNetworkAccessManager *networkMgr;
QNetworkReply *_reply;
public slots:
void replyFinished(QNetworkReply * reply);
};
#endif

DOWNLOADTHREAD.cpp

#include "downloadThread.h"
downloadThread::downloadThread(QObject *parent)
: QThread(parent)
{
}
downloadThread::~downloadThread()
{
quit();
wait();
}
void downloadThread::initDownload()
{
doDownload("http://www.google.com");
exec();
}
void downloadThread::doDownload(QString url)
{
networkMgr = new QNetworkAccessManager;
QNetworkRequest request;
request.setUrl(QUrl(url));
networkMgr->get(request);
connect(networkMgr, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
}
void downloadThread::replyFinished(QNetworkReply * reply)
{
if(reply->error() == QNetworkReply::NoError)
{
QByteArray content = reply->readAll();
QSaveFile file("output.txt");
file.open(QIODevice::WriteOnly);
file.write(content);
file.commit();
reply->deleteLater();
this->exit();
} else {
//error
reply->deleteLater();
this->exit();
}
}

我自己尝试解决问题的事情:

  • 使用delete QCoreAppDLL::pApp
void TestDLL::handleResults(const QString &)
{
debugMsg("result.txt","succes!");
if (QCoreAppDLL::pApp){
QCoreAppDLL::pApp->quit();
delete QCoreAppDLL::pApp;
}
}

正在使主机程序崩溃。

  • QTimer使用和槽(退出())
void TestDLL::initQCoreApp()
{
if (!QCoreApplication::instance())
{
QCoreAppDLL::pApp = new QCoreApplication(QCoreAppDLL::argc, QCoreAppDLL::argv);
TestDLL a;
connect(&a, SIGNAL(finished()), QCoreAppDLL::pApp, SLOT(quit()));
QTimer::singleShot(0, &a, SLOT(startWThread));
QCoreAppDLL::pApp->exec();
}
}

什么也没发生,就像QCoreApplication的exec循环在QThread完成任务之前就结束了。

  • QThread对象上插槽/信号的使用,
void TestDLL::startWThread()
{
downloadThread *thread = new downloadThread(this);
connect(thread, &downloadThread::finished, thread, &QObject::deleteLater);
connect(thread, &downloadThread::resultReady, this, &TestDLL::handleResults);
connect(thread, SIGNAL(finished()), qApp, SLOT(quit()));
thread->start();
}

具有与

相同的行为
void TestDLL::handleResults(const QString &)
{
debugMsg("result.txt","succes!");
if (QCoreAppDLL::pApp)
QCoreAppDLL::pApp->quit();
}

我没有主意了,我还能做些什么来解决这个问题?

提前感谢各位!

我终于自己解决了这个难题。这是给那些感兴趣的人。

我创建了一个新函数:

void TestDLL::deinitQCoreApp()
{
if (QCoreAppDLL::pApp)
delete qApp;
}

现在,我的外部函数变成:

extern "C" TESTCLASS_EXPORT void doDownload()
{
TestDLL a;
a.initQCoreApp();
TestDLL b;
b.deinitQCoreApp();
}

当然,TESTDLL.h有一个新条目:

#ifndef TESTDLL_H
#define TESTDLL_H
#include <QtCore>
#include "testdll_global.h"
#include "libs/downloadThread.h"

class TestDLL : public QObject
{
Q_OBJECT
public slots:
void handleResults(const QString &);
void startWThread();
void initQCoreApp();
void deinitQCoreApp();
private:
void debugMsg(QString fileName, QString message)
{
QFile file(fileName);
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out << message;
file.close();
};
};
#endif

现在,我可以在主机上重用这个函数多少次。问题解决了!

相关内容

  • 没有找到相关文章

最新更新