Embed external exe program in WinForm

1. Demand background

In the development of upper computer software, some tool software is often used, such as modbuspoll, modbusslave, serial port assistant, calculator and other external program software. In addition to upper computer development, in traditional software, if you want to embed The third-party software program is the same. Here, I take the winform form program as an example. The external program is opened in the panel on the right. Note that it is opened in the panel of a form, not outside the form. The purpose is to Embedded in the form to run, I personally figure out how to achieve it. The final effect is this:

 

 The external exe program can minimize, maximize, close the form, etc.

 

 

 There are a lot of articles written in this area on the Internet, a large number of plagiarism, I have not done it myself, and there are still a lot of mistakes. According to those people, it is difficult to make it, the effect is poor, the process is not complete and clear, and the thinking is confused. , the key is misleading, and my article is detailed and feasible, completely sorted out and tested by myself, and the effect is leveraged. It would be a great honor to provide you with some useful meaning

2. Development environment

VS2019,.NetFramework4.7.2

External programs: modbus poll, serial port debugging assistant, windows built-in calculator

3. Implementation process

 1. Create a winform program project

 

 2. Form interface layout

A menu control on the top, add 3 menu items MenuItem under the menu, and an overall splitcontainer control below, put 3 buttons on the left side of the control, put a panel on the right side, and let the panel be completely filled and docked on the right side, and the control name itself Decide

 3. Compile and generate the project, copy the external program to the debug directory

First generate the project, the debug directory will be automatically created, create a directory under the debug directory of the program, copy your application to the directory,

 

 

 The directory structure and hierarchy here are determined by yourself. In short, copy the external third-party application you want to start in this debug directory. In short, copy the external third-party application you want to start in this debug directory.

4. Write control code

 All complete code is:

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. Run the project

The effect is pretty cool, absolutely handsome, and it's not a plagiarized article copied by some idiots on the Internet.

Guess you like

Origin blog.csdn.net/hqwest/article/details/131653198