近期,研究了下将qt程序封装成dll,与其他程序(mfc、c#)进行调用交互,主要涉及几个方面内容:
一、qt生成dll
按照qt官方引导,可以很简单的生成dll,但是此类dll只能与qt程序进行交互;由于qt 的事件循环机制与windows寻坏机制不同,要想在其他程序中启动qt的dll,必须加入QApplication,以启动qt的事件循环机制。
通过官方发布的qtwinmigrate文件,可以非常方便的实现dll。加载exmaples/qtdll的.pro工程文件,在qtcreator可以看到main.cpp有这两个函数
BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpvReserved*/ )
{
//此蔚dll的入口函数
static bool ownApplication = FALSE;
//启动QAppliction,具体见帮助说明
if ( dwReason == DLL_PROCESS_ATTACH )
ownApplication = QMfcApp::pluginInstance( hInstance );
if ( dwReason == DLL_PROCESS_DETACH && ownApplication )
delete qApp;
return TRUE;
}
//建立导出函数
extern "C" __declspec(dllexport) bool showDialog( HWND parent )
{
QWinWidget win( parent );
win.showCentered();
QMessageBox::about( &win, "About QtMfc", "QtMfc Version 1.0\nCopyright (C) 2003" );
return TRUE;
}
qtdll工程实际引入了qtwinmigrate的三个头文件,qmafcapp、qwinhost、qwinwidget,能够连接qt程序与其他外部程序,具体功能看帮助。
在qtdll工程的基础上,将我自己的工程加入,并修改导出函数
主要是把QMessageBox换成我自己的主窗口,记得设置widget
setwindowflag(Qt::window);
setwindowModality(Qt::applicationModal);
编译后,即可生成dll。
二、调用dll
通过mfc程序调用qt 的dll,具体过程比较简单:
首先建立句柄,loadlibrary(“.dll”)
建立导出函数的指针 typedef bool(*pFun)(HWND)
将导出函数赋值给新建立的函数指针。pFun fun = (fun)GetProcAddress(hdll, "showDIalog");
调用函数即可
最后freelibrary()。
具体实现可见qtwinmigrate/exmaples/mfc/step1
问题:这样实现基本可以调用dll,但是在调用dll形成gui程序时,如果将gui程序的子窗口关闭,父窗口也自动关闭
解决方法:猜测是因为子窗口关闭时,自动退出来qt的消息循环,导致所有gui程序全部关闭,通过修改main.cpp文件的两个函数可以解决
1.注释掉if(dwReason == DLL_PROCESS_ATTACH)整句话,取消lQApplication的建立;
2.将showDialog改成int main(int argc, char* argv[])形式,并在函数中创建QApplication,形成qt的事件循环
3.在mfc主程序中,修改导出函数相应参数。
重新编译即可,实现dll的调用
三、dll调用主程序
原理与主程序调用dll基本一致,采用的是回调函数的方式(主要根据这篇文章http://lishutong.me/1075.html)
在qt程序中
typedef void (*pFUn)(int* pVal);
pFun pCallBack = NULL;
建立导出函数,函数参数是pFun,并将该参数赋值给pCallBack;
qt程序在运行到符合调用条件的情况时,调用pCallBack(int*)。
在mfc程序中
typedef void (*pFun)(int *);
typedef void (*init)fun_t)(pFUn);//参数是函数指针类型
void showFun(int *)
在程序某个函数下,
init_fun_t init = (init_fun_t)GetProcessAddress(hdll, "main")
init(showFun);
整个过程其实就是主程序通过导出函数将自己的函数指针发送给dll,dll收到指针后,在运行到符合条件的情况下,调用指针函数,将dll产生的值传送给主程序函数。
(PS:很久没写了,有点乱呵呵)