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

WPF嵌入外部exe应用程序

使用场景

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

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

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

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

功能实现

嵌入基本功能实现

1.导入windows API

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

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

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

csharp 复制代码
[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运行外部程序(以画图程序为示例),需要将外部程序设置为正常的窗体样式,最大化状态的窗体无法嵌入。

csharp 复制代码
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的窗体句柄

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

4. 嵌入窗体

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

csharp 复制代码
 SetParent(appWin, hwnd);

效果如下:

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

5.设置子窗体位置

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

csharp 复制代码
  MoveWindow(appWin, 0, 0, 500, 400, true);

效果:

整个代码

完整实现的代码:

csharp 复制代码
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暂时没有解决办法,只能避免。
相关推荐
largecode10 小时前
座机号码认证如何操作?申请热线实名名片,树立统一官方客服形象
linux·sql·华为·c#·.net·wpf·harmonyos
小满Autumn12 小时前
WPF 入门:XAML 语法、布局与数据绑定
microsoft·c#·.net·wpf
小满Autumn17 小时前
WPF 进阶:样式、触发器与控件模板
c#·.net·wpf
她说彩礼65万1 天前
WPF视觉树 逻辑树
wpf
贺国亚2 天前
分布式并发
分布式·wpf
Iawfy_2 天前
WPF的ComboBox绑定Enum枚举
wpf
她说彩礼65万2 天前
WPF TemplateBinding
wpf
她说彩礼65万2 天前
WPF 三大模板类型 四大属性名称
wpf
无心水2 天前
金融系统数据一致性之战:联机交易与批量作业的冲突处理完全指南
人工智能·金融·wpf·批量作业·顶尖架构师·联机交易·金融架构师
步步为营DotNet3 天前
深入.NET 11:ASP.NET Core 10 在构建高可用分布式系统的关键技术与实践
asp.net·.net·wpf