某些特殊场景,我们要在主程序中嵌套第三方程序。这样臃肿的设计好比,在乡村小楼里面建设一个商业广场,本人不是很喜欢。Qt的QProcess和QWindow可以为我们完成这样的任务,核心思路即
- QProcess启动第三方exe,获取进程ID
- winApi通过进程ID获取窗口句柄
- QWindow::fromWinId(WId id)创建window
- window代理的widget,即我们常见的QWidget
最好的是,第三方exe也是Qt开发的app。下面就是这样的情况
第三方exe
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// OtherWidget inherit from QWidget
OtherWidget w;
w.setWindowFlags(w.windowFlags() | Qt::FramelessWindowHint);
w.show();
return a.exec();
}
如上,OtherWidget继承于QWidget ,如果继承QMainWindow,在嵌入后更改主窗口size时出现丢失。
嵌套
// 枚举窗口参数
typedef struct
{
HWND hwndWindow; // 窗口句柄
DWORD dwProcessID; // 进程ID
}EnumWindowsArg;
// 枚举窗口回调函数
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
EnumWindowsArg *pArg = (EnumWindowsArg *)lParam;
DWORD dwProcessID = 0;
// 通过窗口句柄取得进程ID
::GetWindowThreadProcessId(hwnd, &dwProcessID);
if (dwProcessID == pArg->dwProcessID)
{
pArg->hwndWindow = hwnd;
// 找到了
return FALSE;
}
// 没找到
return TRUE;
}
// 通过进程ID获取窗口句柄
HWND GetWindowHwndByPID(DWORD dwProcessID)
{
HWND hwndRet = NULL;
EnumWindowsArg ewa;
ewa.dwProcessID = dwProcessID;
ewa.hwndWindow = NULL;
EnumWindows(EnumWindowsProc, (LPARAM)&ewa);
if (ewa.hwndWindow)
{
hwndRet = ewa.hwndWindow;
}
return hwndRet;
}
QString cusExePath = "D:/VSpro/mainpro/x64/Debug/mainpro.exe";
QString otherPath = "D:/QtProject/build-ModelDemo-Desktop_Qt_5_10_0_MSVC2015_64bit-Debug/debug/ModelDemo.exe";
QStringList exePathList;
exePathList << cusExePath << otherPath;
for(int i = 0; i < exePathList.length(); i++){
QProcess *process = new QProcess;
QString path = exePathList.at(i);
// 启动 第三方 exe, exepath 含有空格时,再次填充path即可
if(path.contains(" ")){
process->start(path, QStringList() << path);
}
else{
process->start(path);
}
m_listProcess << process;
qint64 proID = process->processId();
HWND wid = NULL;
do{
wid = GetWindowHwndByPID(proID);
if(wid){
break;
}
}while(1);
// window
QWindow *window;
window = QWindow::fromWinId((WId)wid);
// proxyWidget
QWidget *widget;
widget = QWidget::createWindowContainer(window,this);
ui->tabWidget->addTab(widget,QString::number(ui->tabWidget->count()));
}
如上,我们开启了2个Qt APP exe,对于exePath含有空格的进行处理,结合winApi实现窗口句柄的获取,剩下的就很好办了。
退出
开启的第三方程序与主程序的依附问题,进程杀死等。对此的方法也很多
void MainWindow::closeEvent(QCloseEvent *event)
{
for(auto &one : m_listProcess){
one->close();
}
}
当然,如果时其他开发的App,嵌套中会出现问题,所以还是说,小楼里面开商场,搞笑。