在非Qt应用程序中使用基于Qt的DLL [英] Using a Qt-based DLL in a non-Qt application
问题描述
我的客户有一组我正在开发基于Qt的客户端服务器的东西,有很多有趣的小部件的东西和套接字。
公司内的另一个组织希望使用基于QTcpSocket的客户端数据提供者类的封装版本。 (这基本上是什么样的,从服务器提供数据到客户端显示)
然而,该组有一个巨大的应用程序主要使用MFC,这是根本不会随便改变。基于Qt的DLL也是延迟加载,以便在某些配置中可以部署该功能。
我已经工作了,但这有点黑客。这是我现在的解决方案:
DLL包装器类构造函数调用QCoreApplication :: instance()来查看它是否为NULL。如果它是NULL,它假定它在一个非Qt应用程序中,并创建一个自己的QCoreApplication实例:
if(QCoreApplication :: instance()== NULL)
{
int argc = 1;
char * argv [] = {dummy.exe,NULL};
d-> _app = new QCoreApplication(argc,argv); //安全吗
}
else
d-> _app = NULL;
然后将设置一个Windows计时器偶尔调用processEvents():
if(eventTimerInterval> 0)
{
// STATE:启动定时器来偶尔处理事件中的Qt事件队列
SetTimer(NULL,(UINT_PTR)this,eventTimerInterval,CDatabaseLayer_TimerCallback);
}
回调简单地使用timerID作为指针来调用processEvents()函数类实例。 SetTimer()文档说HWND为NULL时,它会忽略timerID,因此看起来完全有效。
VOID CALLBACK BLAHBLAH_TimerCallback (HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime)
{
((BLAHBLAH *)idEvent) - > processEvents(); //基本上只是调用d-> _app-> processEvents();
}
然后我将毁灭QCoreApplication实例作为析构函数中的最后一件事。 / p>
BLAHBLAH ::〜BLAHBLAH()
{
..其他东西
QCoreApplication * app = d-> _app;
d-> _app = NULL;
删除d;
if(app!= NULL)
删除应用程序;
}
如果托管应用程序希望对processEvents()本身进行调用,它可以为eventTimerInterval传递0,并调用BLAHBLAH :: processEvents()本身。
有什么想法?将该应用移植到Qt是不可选的。这不是我们的。
似乎有效,但在这里可能有几个假设被破坏。我可以用这样的虚拟参数构造QCoreApplication吗?事件队列是否安全地以这种方式运作?
我不想让我以后再次吹起来。思想?
学习Qt代码似乎需要QCoreApplication来调度系统范围的消息,如定时器事件。像信号/插槽甚至QThreads这样的事情不依赖于它,除非它们与这些系统范围的消息相关。这是我在一个共享库(以跨平台的方式使用Qt本身)这样做的,我实际上调用 exec ,因为只有processEvents()不处理一切
我有一个全局命名空间:
//私有Qt应用程序
命名空间QAppPriv
{
static int argc = 1;
static char * argv [] = {sharedlib.app,NULL};
static QCoreApplication * pApp = NULL;
static QThread * pThread = NULL;
};
我在QObject OpenApp 方法>(这是moc'ed)这样:
//初始化应用程序
if(QAppPriv :: pThread == NULL)
{
//应用程序线程的单独线程
QAppPriv :: pThread = new QThread();
//直接连接是必需的
connect(QAppPriv :: pThread,SIGNAL(started()),这个,SLOT(OnExec()),Qt :: DirectConnection);
QAppPriv :: pThread-> start();
}
这里是OnExec 插槽:
if(QCoreApplication :: instance()== NULL)
{
QAppPriv :: pApp = new QCoreApplication QAppPriv :: argc,QAppPriv :: argv);
QAppPriv :: pApp-> exec();
if(QAppPriv :: pApp)
删除QAppPriv :: pApp;
}
到目前为止,它似乎工作正常,我不知道是否需要要删除最后的应用程序,如果我找到某些东西,我会更新我的答案。
Am I doing it right?
A client of mine has a group where I'm developing Qt-based client-server stuff with a lot of fun widget stuff and sockets.
Another group within the company wants to use a wrapped version of the QTcpSocket-based client data provider classes. (Which does basically what it sounds like, provides data from the server to the client displays)
However, that group has a huge application built mostly with MFC, and that is simply not going to change any time soon. The Qt-based DLL is also delay-loading so that it can be deployed without this feature in certain configurations.
I've got it working, but it's a little hacky. Here's my solution at the moment:
The DLL wrapper class constructor calls QCoreApplication::instance() to see if it's NULL or not. If it's NULL, it assumes it's in a non-Qt app, and creates a QCoreApplication instance of it's own:
if (QCoreApplication::instance() == NULL)
{
int argc = 1;
char* argv[] = { "dummy.exe", NULL };
d->_app = new QCoreApplication(argc, argv); // safe?
}
else
d->_app = NULL;
It then will set up a windows timer to occasionally call processEvents():
if (eventTimerInterval > 0)
{
// STATE: start a timer to occasionally process the Qt events in the event queue
SetTimer(NULL, (UINT_PTR)this, eventTimerInterval, CDatabaseLayer_TimerCallback);
}
The callback simply calls the processEvents() function using the timerID as a pointer to the class instance. The SetTimer() docs say when HWND is NULL it ignores the timerID, so this appears to be perfectly valid.
VOID CALLBACK BLAHBLAH_TimerCallback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
((BLAHBLAH*)idEvent)->processEvents(); // basically just calls d->_app->processEvents();
}
I then destroy the QCoreApplication instance as the very last thing in the destructor.
BLAHBLAH::~BLAHBLAH()
{
.. other stuff
QCoreApplication* app = d->_app;
d->_app = NULL;
delete d;
if (app != NULL)
delete app;
}
If the hosting application wishes to time the calls to processEvents() itself, it can pass 0 in for eventTimerInterval and call BLAHBLAH::processEvents() itself.
Any thoughts on this? Porting that app to Qt is not an option. It's not ours.
It appears to work, but there are probably several assumptions being broken here. Can I just construct a QCoreApplication with dummy arguments like that? Is the event queue safe to operate in this manner?
I don't want this blowing up in my face later. Thoughts?
Studying the Qt code it seems QCoreApplication is needed to dispatch system-wide messages such as timer events. Things like signal/slots and even QThreads do not depend on it unless they are related to those system-wide messages. Here is how I do this in a shared library (in a cross platform way using Qt itself) and I actually do call exec, because processEvents() alone does not process everything.
I have a global namespace:
// Private Qt application
namespace QAppPriv
{
static int argc = 1;
static char * argv[] = {"sharedlib.app", NULL};
static QCoreApplication * pApp = NULL;
static QThread * pThread = NULL;
};
I have an OpenApp method in a QObject (that is moc'ed) like this:
// Initialize the app
if (QAppPriv::pThread == NULL)
{
// Separate thread for application thread
QAppPriv::pThread = new QThread();
// Direct connection is mandatory
connect(QAppPriv::pThread, SIGNAL(started()), this, SLOT(OnExec()), Qt::DirectConnection);
QAppPriv::pThread->start();
}
And here is OnExec slot:
if (QCoreApplication::instance() == NULL)
{
QAppPriv::pApp = new QCoreApplication(QAppPriv::argc, QAppPriv::argv);
QAppPriv::pApp->exec();
if (QAppPriv::pApp)
delete QAppPriv::pApp;
}
So far it seems to be working fine, I am not sure if I need to delete the app at the end, I will update my answer if I find something.
这篇关于在非Qt应用程序中使用基于Qt的DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!