WinForm中嵌入外部exe程序

一、需求背景

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

WinForm中嵌入外部exe程序_第1张图片

WinForm中嵌入外部exe程序_第2张图片

 WinForm中嵌入外部exe程序_第3张图片

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

WinForm中嵌入外部exe程序_第4张图片

 WinForm中嵌入外部exe程序_第5张图片

 WinForm中嵌入外部exe程序_第6张图片

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

二、开发环境

VS2019,.NetFramework4.7.2

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

三、实现过程

 1、创建winform程序项目

WinForm中嵌入外部exe程序_第7张图片

 WinForm中嵌入外部exe程序_第8张图片

 2、窗体界面布局

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

WinForm中嵌入外部exe程序_第9张图片

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

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

WinForm中嵌入外部exe程序_第10张图片

 WinForm中嵌入外部exe程序_第11张图片

 WinForm中嵌入外部exe程序_第12张图片

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

4、写控件代码

WinForm中嵌入外部exe程序_第13张图片

WinForm中嵌入外部exe程序_第14张图片

 全部完整代码是:

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();
        }

        /// 
        /// modbuspoll
        /// 
        /// 
        /// 
        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);
        }

        /// 
        ///  modbuspoll
        /// 
        /// 
        /// 
        private void modbusPollToolStripMenuItem_Click(object sender, EventArgs e)
        {
            btn_ModPoll_Click(null, null);
        }

        /// 
        /// 串口助手
        /// 
        /// 
        /// 
        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);
        }
        /// 
        /// 串口助手
        /// 
        /// 
        /// 
        private void 串口助手ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            btn_Serial_Click(null, null);
        }

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

    /// 
    /// 嵌入外部exe工具类
    /// 
    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);
            } 
        }

        /// 
        /// 加载外部exe程序到程序容器中
        /// 
        /// exe容器控件
        /// exe绝对路径
        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);
            } 
        }

        /// 
        /// 确保应用程序嵌入此容器
        /// 
        /// 
        /// 
        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);
        }

        /// 
        /// 将指定的程序嵌入控件中
        /// 
        /// 进程名称
        /// 控件名称
        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));
            }
        }
        /// 
        /// 嵌入容器大小改变事件
        /// 
        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、运行项目

WinForm中嵌入外部exe程序_第15张图片

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

WinForm中嵌入外部exe程序_第16张图片

你可能感兴趣的:(C#上位机开发笔记,winform,c#,外部程序,exe,上位机)