問題描述
我做對了嗎?
我的一個客戶有一個小組,我在那里開發基于 Qt 的客戶端-服務器內容,其中包含許多有趣的小部件和套接字.
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.
公司內的另一個小組想要使用基于 QTcpSocket 的客戶端數據提供程序類的包裝版本.(基本上就是它聽起來的樣子,從服務器向客戶端顯示提供數據)
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)
但是,該小組有一個主要使用 MFC 構建的龐大應用程序,而且這種情況在短期內不會改變.基于 Qt 的 DLL 也是延遲加載的,因此在某些配置中可以在沒有此功能的情況下部署它.
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.
我已經讓它工作了,但它有點hacky.這是我目前的解決方案:
I've got it working, but it's a little hacky. Here's my solution at the moment:
DLL 包裝類構造函數調用 QCoreApplication::instance() 來查看它是否為 NULL.如果它為 NULL,則假定它在非 Qt 應用程序中,并創建它自己的 QCoreApplication 實例:
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;
然后它會設置一個windows定時器來偶爾調用processEvents():
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);
}
回調只是使用 timerID 作為指向類實例的指針來調用 processEvents() 函數.SetTimer() 文檔說,當 HWND 為 NULL 時,它會忽略 timerID,因此這似乎是完全有效的.
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();
}
然后我銷毀 QCoreApplication 實例作為析構函數中的最后一件事.
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;
}
如果托管應用程序希望自己對 processEvents() 的調用計時,它可以為 eventTimerInterval 傳遞 0 并調用 BLAHBLAH::processEvents() 本身.
If the hosting application wishes to time the calls to processEvents() itself, it can pass 0 in for eventTimerInterval and call BLAHBLAH::processEvents() itself.
對此有什么想法嗎?將該應用程序移植到 Qt 不是一種選擇.這不是我們的.
Any thoughts on this? Porting that app to Qt is not an option. It's not ours.
它似乎有效,但這里可能有幾個假設被打破.我可以用這樣的虛擬參數構造一個 QCoreApplication 嗎?事件隊列以這種方式運行是否安全?
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?
推薦答案
研究 Qt 代碼,似乎需要 QCoreApplication 來調度系統范圍的消息,例如計時器事件.諸如信號/插槽甚至 QThread 之類的東西都不依賴于它,除非它們與那些系統范圍的消息相關.這是我在共享庫中執行此操作的方法(以跨平臺方式使用 Qt 本身)并且我實際上確實調用了 exec,因為 processEvents() 本身并不能處理所有內容.
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;
};
我在 QObject 中有一個 OpenApp 方法(即 moc'ed),如下所示:
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();
}
這里是 OnExec 插槽:
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的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!