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

使用场景

在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暂时没有解决办法,只能避免。

猜你喜欢

转载自blog.csdn.net/qq_39427511/article/details/131755575