QT-窗口嵌入外部exe

窗口类:

#pragma once
#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QProcess>
#include <QTimer>
#include <QDebug>
#include <Windows.h>
#include <QWindow>
#include <QResizeEvent>

class ExternalAppWidget : public QWidget 
{
	Q_OBJECT

public:
	ExternalAppWidget(QString exePath, QString strTitle, QWidget *parent = nullptr);
	~ExternalAppWidget();

private:
	bool checkAppStartDone(QString strAppTitle);
	void killProcessByExeName(QString processName);

protected:
	void resizeEvent(QResizeEvent *event);

private:
	QVBoxLayout *m_pLayout;
	QProcess	*m_pProcess;
	QWidget		*m_pExternalWindow;
	QString		m_strExePath;
	QString		m_strExeTile;
};
#include "externalAppWidget.h"
#include <QFileInfo>
#include <QDir>
#include <QThread>
#include <QMessageBox>
#include <QTime>

// 不阻塞定时器
struct sTimeout
{
	QTime time;
	uint32_t interval;

	void start(uint32_t t)
	{
		interval = t;
		time.start();
	};

	bool isTimeOut()
	{
		return time.elapsed() > interval;
	};
};

ExternalAppWidget::ExternalAppWidget(QString exePath, QString strTitle,QWidget *parent) :
	QWidget(parent),
	m_pExternalWindow(nullptr)
	, m_strExePath(exePath)
	, m_strExeTile(strTitle)
{
	QFileInfo fileInfo(exePath);
	killProcessByExeName(fileInfo.fileName());
	m_pLayout = new QVBoxLayout(this);

	// 启动外部程序
	m_pProcess = new QProcess(this);
	m_pProcess->setWorkingDirectory(fileInfo.absolutePath());
	m_pProcess->start(exePath); 
	m_pProcess->waitForStarted();
	checkAppStartDone(m_strExeTile);

	// 获取外部程序的窗口句柄
	HWND hwnd = FindWindowW(NULL, reinterpret_cast<LPCWSTR>(m_strExeTile.utf16()));
	if (hwnd)
	{
				// 修改窗口样式以去掉标题栏
		LONG style = GetWindowLong(hwnd, GWL_STYLE);
		style &= ~(WS_CAPTION | WS_THICKFRAME); // 移除标题栏和边框
		SetWindowLong(hwnd, GWL_STYLE, style | WS_POPUP); // 设置为无边框的弹出窗口
		ShowWindow(hwnd, SW_SHOW);
	
		WId wid = (WId)hwnd;
		QWindow *pQwindow;
		pQwindow = QWindow::fromWinId(wid);

		// 创建窗口容器
		m_pExternalWindow = QWidget::createWindowContainer(pQwindow, this);
		m_pExternalWindow->setAttribute(Qt::WA_NativeWindow);
		m_pExternalWindow->setMinimumSize(100, 100);
		m_pLayout->addWidget(m_pExternalWindow);
		m_pLayout->setMargin(0);		
	}
	else
	{
		//QMessageBox::information(0, "Tip", QString("未找到窗口:%1").arg(m_strExeTile), QMessageBox::Yes);
		qDebug() << "Failed to find external application window.";
	}

	setLayout(m_pLayout);
}

ExternalAppWidget::~ExternalAppWidget()
{
	QFileInfo fileInfo(m_strExePath);
	killProcessByExeName(fileInfo.fileName());
}

bool ExternalAppWidget::checkAppStartDone(QString strAppTitle)
{
	// 循环检查窗口是否存在
	QString windowTitle = strAppTitle;
	HWND hwnd = nullptr;

	int nStep = 0;
	sTimeout timeout;
	while (true)
	{
		Sleep(5);
		switch (nStep)
		{
		case 0:
		{
			timeout.start(30*1000);
			nStep = 1;
		}break;

		case 1:
		{
			hwnd = FindWindowW(NULL, reinterpret_cast<LPCWSTR>(windowTitle.utf16()));
			if (hwnd != NULL)
			{
				return true; // 找到窗口,退出循环
			}
			else if (timeout.isTimeOut())
			{
				return false;
			}
		}break;
		default:
			break;
		}

	}


	return false;

}

void ExternalAppWidget::killProcessByExeName( QString processName)
{
	QStringList params;
	params << "-f" << "-im" << processName;
	QProcess process;
	process.start("taskkill", params);
	process.waitForFinished();
}

void ExternalAppWidget::resizeEvent(QResizeEvent *event) {
	QWidget::resizeEvent(event);
	if (m_pExternalWindow) {
		m_pExternalWindow->resize(event->size());
	}
}

应用层调用

void cWinDebug::initRemoteDesktopWidget()
{
	for (int i = 1; i <= DEV_MAX_COUNT; i++)
	{
		QString strTitleName = GET_PARAM_STRING(P_EXE_TITLE_NAME(i));
		QString strTabName = GET_PARAM_STRING(P_TAB_NAME(i));
		QString strExePath = GET_PARAM_STRING(P_EXE_PATH(i));

		if (strExePath.isEmpty() || strTitleName.isEmpty() || strTabName.isEmpty())
		{
			continue;
		}

		ExternalAppWidget* e = new ExternalAppWidget(strExePath, strTitleName, this);
		e->showMaximized();
		ui.tabWidgetRemote->insertTab(0, (QWidget*)e, strTabName);
	}

	ui.tabWidgetRemote->setCurrentIndex(0);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/950118.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何有效搭建在线培训知识库

在当今快速发展的教育行业&#xff0c;知识的更新速度日益加快&#xff0c;教育机构和企业需要为学员提供持续的学习资源和培训支持。在线培训知识库的搭建成为实现这一目标的重要手段。一个有效的在线培训知识库不仅能够帮助学员系统地学习和掌握知识&#xff0c;还能为教师和…

Android Audio基础(54)——数字音频接口 I2S、PCM(TDM) 、PDM

1. 概述 本文介绍的数字音频接口全部是硬件接口,是实际的物理连线方式,即同一个PCB板上IC芯片和IC芯片之间的通讯协议。 PCM、PDM也可以用于表示音频编码格式,。编码格式是指模拟信号数字化的方式。 I2S和PCM(TDM)接口传输的数据是PCM格式的音频数据。这两种协议是最为常见…

STM32之CAN通讯(十一)

STM32F407 系列文章 - CAN通讯&#xff08;十一&#xff09; 目录 前言 一、CAN 二、CAN驱动电路 三、CAN软件设计 1.CAN状态初始化 2.头文件相关定义 3.接收中断服务函数 4.用户层使用 1.用户层相关定义 2.发送数据 3.接收数据 1.查询方式处理 2.中断方式处理 3…

第31天:Web开发-PHP应用TP框架MVC模型路由访问模版渲染安全写法版本漏洞

#知识点 1、安全开发-框架技术-ThinkPHP 2、安全开发-框架安全-版本&写法 3、安全开发-ThinkPHP-代码审计案例 类别 组件/框架 说明 [Web框架] Laravel 现代化、功能全面的框架&#xff0c;适合大多数Web应用。 Symfony 高度模块化、功能强大的框架&#xff0c;适…

量子计算遇上人工智能:突破算力瓶颈的关键?

引言&#xff1a;量子计算遇上人工智能——突破算力瓶颈的关键&#xff1f; 在数字化时代的浪潮中&#xff0c;人工智能&#xff08;AI&#xff09;正以前所未有的速度改变着我们的生活&#xff0c;从语音助手到自动驾驶&#xff0c;从医学诊断到金融分析&#xff0c;无不彰显其…

英伟达 RTX 5090 显卡赋能医疗大模型:变革、挑战与展望

一、英伟达 RTX 5090 与 RTX 4090 技术参数对比 1.1 核心架构与制程工艺 在探讨英伟达 RTX 4090 与 RTX 5090 的差异时&#xff0c;核心架构与制程工艺无疑是最为关键的基础要素&#xff0c;它们从根本上决定了两款显卡的性能上限与应用潜力。 1.1.1 核心架构差异 RTX 4090…

Bash Shell的操作环境

目录 1、路径与指令搜寻顺序 2、bash的进站&#xff08;开机&#xff09;与欢迎信息&#xff1a;/etc/issue&#xff0c;/etc/motd &#xff08;1&#xff09;/etc/issue &#xff08;2&#xff09;/etc/motd 3、bash的环境配置文件 &#xff08;1&#xff09;login与non-…

homework 2025.01.07 math 6

1选择部分 二填空部分

(六)CAN总线通讯

文章目录 CAN总线回环测试第一种基于板载CAN测试第一步确认板载是否支持第二步关闭 CAN 接口将 CAN 接口置于非活动状态第三步 配置 CAN 接口第一步 设置 CAN 接口比特率第二步 设置 CAN 启用回环模式第三步 启用 CAN 接口 第四步 测试CAN总线回环捕获 CAN 消息发送 CAN 消息 第…

任务调度之Quartz(二):Quartz体系结构

1、Quartz 体系结构 由上一篇的Quartz基本使用可以发现&#xff0c;Quartz 主要包含一下几种角色&#xff1a; 1&#xff09;Job&#xff1a;也可以认为是JobDtetail&#xff0c;表示具体的调度任务 2&#xff09;Trigger&#xff1a;触发器&#xff0c;用于定义任务Job出发执行…

基于Springboot + vue实现的小型养老院管理系统

&#x1f942;(❁◡❁)您的点赞&#x1f44d;➕评论&#x1f4dd;➕收藏⭐是作者创作的最大动力&#x1f91e; &#x1f496;&#x1f4d5;&#x1f389;&#x1f525; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;欢迎留言讨论 &#x1f525;&#x1f525;&…

初学Linux电源管理

学习文档出处&#xff1a; 万字整理 | 深入理解Linux电源管理&#xff1a;万字整理 | 深入理解Linux电源管理-CSDN博客 电源管理 因为设备需要用电&#xff0c;而且设备中的各个硬件所需要的电压是不一样的。故计算机需要对硬件的电源状态管理。但是电能并不是免费的&#x…

React(二)——Admin主页/Orders页面/Category页面

文章目录 项目地址一、侧边栏1.1 具体实现 二、Header2.1 实现 三、Orders页面3.1 分页和搜索3.2 点击箭头显示商家所有订单3.3 页码按钮以及分页 四、Category页面4.1 左侧商品添加栏目4.2 右侧商品上传栏 五、Sellers页面六、Payment Request 页面&#xff08;百万数据加载&a…

刚体变换矩阵的逆

刚体运动中的变换矩阵为&#xff1a; 求得变换矩阵的逆矩阵为&#xff1a; opencv应用 cv::Mat R; cv::Mat t;R.t(), -R.t()*t

IDEA中Maven依赖包导入失败报红的潜在原因

在上网试了别人的八个问题总结之后依然没有解决&#xff1a; IDEA中Maven依赖包导入失败报红问题总结最有效8种解决方案_idea导入依赖还是报红-CSDN博客https://blog.csdn.net/qq_43705131/article/details/106165960 江郎才尽之后突然想到一个原因&#xff1a;<dep…

UVM:uvm_component methods configure

topic UVM component base class uvm_config_db 建议使用uvm_config_db代替uvm_resource_db uvm factory sv interface 建议&#xff1a;uvm_config_db 以下了解 建议打印error

基于时间维度水平拆分的多 TiDB 集群统一数据路由/联邦查询技术的实践

导读 在大数据时代&#xff0c;金融行业面临着日益增长的数据量和复杂的查询需求&#xff0c;尤其是跨库、跨集群的场景。在这种背景下&#xff0c;如何在保证数据一致性、高可用性的同时&#xff0c;实现业务的快速扩展与高效查询&#xff0c;成为了企业数字化转型的关键挑战…

概率论 期末 笔记

第一章 随机事件及其概率 利用“四大公式”求事件概率 加法公式 减法 条件概率公式 全概率公式与贝叶斯公式 伯努利概型求概率 习题 推导 一维随机变量及其分布 离散型随机变量&#xff08;R.V&#xff09;求分布律 利用常见离散型分布求概率 连续型R.V相关计算 利用常见连续…

把vue项目或者vue组件发布成npm包或者打包成lib库文件本地使用

将vue项目发布成npm库文件&#xff0c;第三方通过npm依赖安装使用&#xff1b;使用最近公司接了一个项目&#xff0c;这个项目需要集成到第三方页面&#xff0c;在第三方页面点击项目名称&#xff0c;页面变成我们的项目页面&#xff1b;要求以npm库文件提供给他们&#xff1b;…