WPF嵌入外部exe应用程序-实现基本的嵌入

news2024/11/26 2:52:07

WPF嵌入外部exe应用程序

  • 使用场景
  • 功能实现
    • 嵌入基本功能实现
      • 1.导入windows API
      • 2.运行外部程序
      • 3. 获取窗体句柄
      • 4. 嵌入窗体
      • 5.设置子窗体位置
      • 整个代码
    • 嵌入存在的问题:

使用场景

在WPF桌面应用程序开发过程中,有时候需要将其他程序结合到一起,让他看起来是一个程序,就需要把其他程序的窗口,作为子窗体,嵌入到程序中去。如果都是自己程序,可以将其他程序的项目直接导入引用。

在以下几种情况,可能无法直接修改和调用源程序。

  • 其他人员开发,无法获取源代码,无权对源码进行修改
  • exe并非使用C#相关框架(WPF/Winform)开发,比如用unity开发的程序

这种时候就只能通过直接将打包的exe程序嵌入到当前程序中去。

功能实现

嵌入基本功能实现

1.导入windows API

需要调用Windows API的SetParentMoveWindow,通过DllImport将API加载进来

SetParent通过句柄将一个窗体设为另一个窗体的父窗体。

MoveWindow改变指定窗口的位置和大小.对基窗口来说,位置和大小取决于屏幕的左上角;对子窗口来说,位置和大小取决于父窗口客户区的左上角.对于Owned窗口,位置和大小取决于屏幕左上角.

[DllImport("user32.dll", SetLastError = true)]
public static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
 
[DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);

2.运行外部程序

使用Process运行外部程序(以画图程序为示例),需要将外部程序设置为正常的窗体样式,最大化状态的窗体无法嵌入。

var exeName = "C:\\WINDOWS\\system32\\mspaint";
//使用Process运行程序
Process p = new Process();
p.StartInfo.FileName = exeName;
p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
p.Start();

3. 获取窗体句柄

循环判断运行的外部程序窗体句柄,如果不为零就说明程序已经运行,获取他的句柄。

WPF中控件无法获取句柄,只能获取窗体的句柄,使用WindowInteropHelper获取WPF的窗体句柄

      while (p.MainWindowHandle.ToInt32() == 0)
            {
                System.Threading.Thread.Sleep(100);
            }
            IntPtr appWin = p.MainWindowHandle;
            IntPtr hwnd = new WindowInteropHelper(this).Handle;

4. 嵌入窗体

使用 SetParent将外部程序窗体嵌入当前窗体

 SetParent(appWin, hwnd);

效果如下:

窗体已经嵌入称为当前窗体的子窗体,可以跟随移动,子窗体也无法移出父窗体位置。

在这里插入图片描述

5.设置子窗体位置

嵌入窗体之后,子窗体位置可以随机放置,我们可以通过MoveWindow来设置子窗体的位置和大小

  MoveWindow(appWin, 0, 0, 500, 400, true);

效果:
在这里插入图片描述

整个代码

完整实现的代码:

var exeName = "C:\\WINDOWS\\system32\\mspaint";//嵌入程序路径,可以改成其他程序
//使用Process运行程序
Process p = new Process();
p.StartInfo.FileName = exeName;
p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
p.Start();
//获取窗体句柄
while (p.MainWindowHandle.ToInt32() == 0)
{
    System.Threading.Thread.Sleep(100);
}
IntPtr appWin = p.MainWindowHandle;//子窗体(外部程序)句柄
IntPtr hwnd = new WindowInteropHelper(this).Handle;//当前窗体(主程序)句柄
//设置父窗体(实现窗体嵌入)
SetParent(appWin, hwnd);
//设置窗体位置和大小
MoveWindow(appWin, 0, 0, 500, 400, true);

嵌入存在的问题:

  1. WPF控件无法获取句柄,只能直接在窗体下操作嵌入
  2. 嵌入窗体大小无法实时跟随变化
  3. 嵌入窗体保留了窗体样式和边框,无法现成一个整体
  4. 嵌入窗体永远附在最顶层,会遮挡其他控件

在这里插入图片描述

后续更新:

  1. 通过WindowsFormsHost在WPF中调用winform的控件来解决控件没有句柄问题,进行封装控件,解决问题1和2;
  2. 问题3需要使用其他Windows API来解决;
  3. 问题4暂时没有解决办法,只能避免。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux尖刀——shell

目录 知识点 lsblk grep awk tail du df 对新增存储设备的检测与分区 用lsblk查询块设备 用dmesg看内核打印信息 用ls查看新增设备 对rootfs空间使用情况的监控 知识点 首先想要用shell脚本解决一些问题肯定要熟悉linux的命令 lsblk -t或–tree:以…

Redis进阶底层原理- 缓冲区

Redis中使用了很多缓冲区,在redis各个环节起到了非常核心的作用。下面来一一介绍一下: 输入输出缓冲区(客户端缓冲区) Redis中的输入输出缓冲区是为了平衡客户端发送命令和服务端处理命令的速度差异,如果客户端发送指…

java用 postman输入 数字 会加上单引号 和逗号,方便查询

java用 postman输入 数字 会加上单引号 和逗号,方便查询 /*** 输入12575726* 891006* 12575726* 891006* 返回* 12575726,* 891006,* 12575726,* 891006* 方便查询数据* param data* return*/RequestMapping(value "l…

MySQL查看系统性能参数、统计SQL的查询成本last_query_cost的使用

1、查看MySQL系统性能参数 在MySQL中,可以使用SHOW STATUS语句查询一些MySQL数据库服务器的性能参数、执行频率。 语法如下: SHOW [ GLOBAL | SESSION] STATUS LIKE 参数; 一些常用的性能参数如下: Connections:连接MySQL服…

《银行法律法规》三、银行管理——2、公司治理、 内部控制与合规管理

第二章 公司治理、 内部控制与合规管理 第一节 公司治理 考点1 银行公司治理概述★★ 商业银行公司治理是指股东大会、 董事会、 监事会、 高级管理层、 股东及其他利益相关者之间的相互关系, 包括组织架构、 职责边界、 履职要求等治理制衡机制, 以…

从零到精通!50个必懂IT术语,让你成为行业翘楚!

您刚进入IT行业?不必惊慌!我们为您整理了50个最常见的IT术语,从ICT到ITIL再到SLM,全方位解读,让您快速掌握这些关键概念。更令人兴奋的是,我们将向您介绍轻易云数据集成平台,它是您在数字化转型…

Redis进阶底层原理 - 分区算法方案

Redis分区是指将数据分散到不同的Redis实例,降低单个Redis实例内存和高并发请求的压力。为什么要做分区:目前来说前面所学知识都是基于Redis单实例上进行的,及时是哨兵模式也只是保证了单个Redis实例的可用性。当内存数据越来越多时单个Redis…

BOM编程

十四、BOM和DOM编程 windows对象 常见方法 _self:在当前页面打开窗口 _blank:打开一个新的选项卡 第一个参数是x轴,一般没有横向滚动条,都是操作第二个参数 history对象 属性:一般用不到 方法: 01.histor…

PCB规则设置

PCB设计规则 网络class设置间距规则设置线宽规则过孔规则设置铺铜规则设置其他规则设置 网络class设置 间距规则设置 进入规则设置 线宽规则 新建线宽选项,电源类 过孔规则设置 铺铜规则设置 其他规则设置

Django ORM Field源码解读

已models.py的CharField字段代码为起点 secret_id = models.CharField("secret_id", max_length=256, default="") 构造方法中,会去调父类Field 的构造方法,而后向 CharField 的验证器列表 中添加一个 MaxLengthValidator 对象,用于…

leecode 数据库:1084. 销售分析III

导入数据: Create table If Not Exists Product (product_id int, product_name varchar(10), unit_price int); Create table If Not Exists Sales (seller_id int, product_id int, buyer_id int, sale_date date, quantity int, price int); Truncate table Prod…

Elasticsearch中查询性能优化

Elasticsearch是一种流行的搜索引擎和分布式文档存储解决方案,它的高效性能和可伸缩性使其成为许多应用程序的首选存储引擎。在工作中,优化Elasticsearch的检索性能是一个非常重要的任务,可以大大提高应用程序的响应速度和用户体验。下面我们…

0131 物理层2

目录 2.物理层 2.2传输介质 2.3物理层设备 2.2,2.3部分习题 2.物理层 2.2传输介质 2.3物理层设备 2.2,2.3部分习题 1.利用一根同轴电缆互连主机构成以太网,则主机间得通信方式为() A.全双工 B.半双工 …

PTA天梯赛的赛场安排

天梯赛使用 OMS 监考系统,需要将参赛队员安排到系统中的虚拟赛场里,并为每个赛场分配一位监考老师。每位监考老师需要联系自己赛场内队员对应的教练们,以便发放比赛账号。为了尽可能减少教练和监考的沟通负担,我们要求赛场的安排满…

401 - 未授权: 由于凭据无效,访问被拒绝。

这种原因通常因为将目标文件夹建立在C盘(系统盘),系统盘权限比较高。 解决方案:将 C:\Windows\Temp 设置 User 写权限即可。

简单版本视频播放服务器V2

简单版本视频播放服务器V2 一直想做个家用版本的家庭影院,通过这个服务器可以给电脑,平板,手机等设备提供直接播放电影的作用,通过浏览器就是可以访问电脑里面的视频,实现简单的家庭版本服务了。 备注注意 &#xff1a…

基于linux下的高并发服务器开发(第二章)- 2.4 父子进程虚拟地址空间情况

01 / 进程创建 #include <sys/types.h> #include <unistd.h> pid_t fork(void); 函数的作用&#xff1a;用于创建子进程。 返回值&#xff1a; fork()的返回值会返回两次。一次是在父进程中&#xff0c;一次是在子进程中。 在父进程中返回…

【活动回顾】Data + AI 时代下的云数仓设计 @Qcon

此前&#xff0c;由 InfoQ 中国举办的 QCon 全球软件开发大会在广州圆满落幕。本次大会有近百位国内外技术大咖现场分享前沿技术案例与创新实践&#xff0c;共有十二个专题&#xff0c;近五十余场分享。Databend Cloud 联合创始人张雁飞受邀参与了此次技术盛宴&#xff0c;并在…

SpringBoot整合gRPC - proto3 -- 简单明了

项目结构 pom引入(parent中引入即可) <properties><net-devh-grpc.version>2.14.0.RELEASE</net-devh-grpc.version><os-maven-plugin.version>1.6.0</os-maven-plugin.version><protobuf-maven-plugin.version>0.5.1</protobuf-mave…

基于flask框架的用户注册页面实例

文件框架 app.py文件 from flask import Flask, render_template, requestapp Flask(__name__)app.route(/) def index():return register()# 申请注册页面 app.route(/register, methods["GET"]) def register(): # put applications code herereturn render_tem…