WinForm中嵌入外部exe程序

一、需求背景

在上位机软件开发中,会经常用到一些工具软件,如modbuspoll,modbusslave,串口助手,计算器之类的外部程序软件,除了上位机开发,在传统软件中,如果要在自己的程序中嵌入第三方软件程序,也是一样的,这里,我以winform窗体程序为例,在外部程序在右边的panel中打开,注意是在一个窗体的panel中打开,不是在窗体外打开,目的是嵌入到窗体中运行,本人亲自开搞如何实现。最终的效果是这样的:

 

 外部exe程序可以最小化,最大化,关闭窗体等

 

 

 网上有很多写的这方面文章,大批大批的抄袭,没有自己操作完成过,并且还是错误一大堆,按照那些人写的,很难做出来,效果也差劲,过程也不完整清楚,思路混乱,关键是误导,而我的文章,是详细可行,完全自己整理检验过的,效果杠杠的,如能为你提供一些作用意义,不胜荣幸

二、开发环境

VS2019,.NetFramework4.7.2

外部程序:modbus poll,串口调试助手,windows自带的计算器

三、实现过程

 1、创建winform程序项目

 

 2、窗体界面布局

顶部一个menu控件,menu下添加3个菜单项MenuItem,下面一个整体的splitcontainer控件,控件中左侧放3个button,右侧放一个panel,并让panel在右侧中完全填充停靠,控件命名自己决定

 3、编译生成项目,复制外部程序到debug目录

首先生成项目,将会自动创建debug目录,在程序的debug目录下,创建目录,将你的应用程序复制到目录下,

 

 

 这里的目录结构和层次自己决定,总之就是将你想要启动的外部第三方应用程序复制放在这个debug目录下,总之就是将你想要启动的外部第三方应用程序复制放在这个debug目录下

4、写控件代码

 全部完整代码是:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EmbedProcessApp
{
    public partial class FrmMain : Form
    {
        public FrmMain()
        {
            InitializeComponent();
        }

        /// <summary>
        /// modbuspoll
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_ModPoll_Click(object sender, EventArgs e)
        {
            EmbeddedExeTool exetool = new EmbeddedExeTool();
            string path = Application.StartupPath + "\\Party3Tools\\ModbusPoll\\ModbusPoll.exe"; //debug下面的文件夹
            exetool.LoadEXE(MainPanel, path);
        }

        /// <summary>
        ///  modbuspoll
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void modbusPollToolStripMenuItem_Click(object sender, EventArgs e)
        {
            btn_ModPoll_Click(null, null);
        }

        /// <summary>
        /// 串口助手
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Serial_Click(object sender, EventArgs e)
        {
            EmbeddedExeTool exetool = new EmbeddedExeTool();
            string path = Application.StartupPath + "\\Party3Tools\\SerialHelper\\ComMonitor.exe"; //debug下面的文件夹
            exetool.LoadEXE(MainPanel, path);
        }
        /// <summary>
        /// 串口助手
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 串口助手ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            btn_Serial_Click(null, null);
        }

        /// <summary>
        /// 计算器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_mycalc_Click(object sender, EventArgs e)
        {
            EmbeddedExeTool exetool = new EmbeddedExeTool();
            string path = "calc.exe";  
            exetool.LoadEXE(MainPanel, path);
        }
        /// <summary>
        /// 计算器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 计算器ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            btn_mycalc_Click(null, null);
        }
    }

    /// <summary>
    /// 嵌入外部exe工具类
    /// </summary>
    public class EmbeddedExeTool
    {
        [DllImport("User32.dll", EntryPoint = "SetParent")]
        private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll", EntryPoint = "ShowWindow")]
        private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
        //[DllImport("user32.dll")]
        //private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
        //[DllImport("user32.dll")]
        //private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
        //[DllImport("user32.dll", SetLastError = true)]
        //private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        IntPtr WindowHandle = IntPtr.Zero;
        private const int WS_THICKFRAME = 262144;
        private const int WS_BORDER = 8388608;
        private const int GWL_STYLE = 16;//也可以是-16
        private const int WS_CAPTION = 0xC00000;
        private Process proApp = null;//进程名称
        private Control ContainerControl = null;//控件名称
        private const int WS_VISIBLE = 0x10000000;
        [DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
        private static extern IntPtr SetWindowLongPtr32(HandleRef hWnd, int nIndex, int dwNewLong);
        [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)]
        private static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, int dwNewLong); 
        private IntPtr SetWindowLong(HandleRef hWnd, int nIndex, int dwNewLong)
        {
            if (IntPtr.Size == 4)//32位程序
            {
                return SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
            }
            else//64位程序
            {
                return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
            } 
        }

        /// <summary>
        /// 加载外部exe程序到程序容器中
        /// </summary>
        /// <param name="control">exe容器控件</param>
        /// <param name="exepath">exe绝对路径</param>
        public void LoadEXE(Control control, string exepath)
        {
            if (this.proApp == null || this.proApp.HasExited)//如果进程为空或进程已关闭
            {
                ContainerControl = control;
                control.SizeChanged += Control_SizeChanged;
                //进程启动信息
                ProcessStartInfo info = new ProcessStartInfo(exepath);
                info.WindowStyle = ProcessWindowStyle.Normal;
                info.UseShellExecute = false;
                info.CreateNoWindow = false;
                //启动进程
                proApp = Process.Start(info);
                Application.Idle += Application_Idle;//添加事件,即当应用程序处理完成进入空闲状态时触发的事件
                EmbedProcess(proApp, control);
            } 
        }

        /// <summary>
        /// 确保应用程序嵌入此容器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Application_Idle(object sender, EventArgs e)
        {
            if (this.proApp == null || this.proApp.HasExited)//如果进程为空或进程已退出
            {
                this.proApp = null;
                Application.Idle -= Application_Idle;//移除事件,即当应用程序处理完成进入空闲状态时触发的事件
                return;
            }
            if (proApp.MainWindowHandle == IntPtr.Zero)
            {
                return;
            }
            Application.Idle -= Application_Idle;
            EmbedProcess(proApp, ContainerControl);
        }

        /// <summary>
        /// 将指定的程序嵌入控件中
        /// </summary>
        /// <param name="app">进程名称</param>
        /// <param name="control">控件名称</param>
        private void EmbedProcess(Process app, Control control)
        { 
            if (app == null || app.MainWindowHandle == IntPtr.Zero || control == null)
            {
                return;
            }
            try
            {
                SetParent(app.MainWindowHandle, control.Handle); //设置父窗体
                SetWindowLong(new HandleRef(this, app.MainWindowHandle), GWL_STYLE, WS_VISIBLE);//去除边框
                ShowWindow(app.MainWindowHandle, (int)ProcessWindowStyle.Maximized);//显示窗体
                MoveWindow(app.MainWindowHandle, 0, 0, control.Width, control.Height, true);//移动窗体
            }
            catch (Exception ex3)
            {
              MessageBox.Show((ex3.Message));
            }
        }
        /// <summary>
        /// 嵌入容器大小改变事件
        /// </summary>
        private void Control_SizeChanged(object sender, EventArgs e)
        {
            if (proApp == null)
            {
                return;
            }
            if (proApp.MainWindowHandle != IntPtr.Zero && ContainerControl != null)
            {
                MoveWindow(proApp.MainWindowHandle, 0, 0, ContainerControl.Width, ContainerControl.Height, true);
            }
        }
    }


}

5、运行项目

效果相当屌,绝对帅,可不是网上一些傻子的抄袭复制的文章。

  • 8
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hqwest

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值