在上位机软件开发中,会经常用到一些工具软件,如modbuspoll,modbusslave,串口助手,计算器之类的外部程序软件,除了上位机开发,在传统软件中,如果要在自己的程序中嵌入第三方软件程序,也是一样的,这里,我以winform窗体程序为例,在外部程序在右边的panel中打开,注意是在一个窗体的panel中打开,不是在窗体外打开,目的是嵌入到窗体中运行,本人亲自开搞如何实现。最终的效果是这样的:
外部exe程序可以最小化,最大化,关闭窗体等
网上有很多写的这方面文章,大批大批的抄袭,没有自己操作完成过,并且还是错误一大堆,按照那些人写的,很难做出来,效果也差劲,过程也不完整清楚,思路混乱,关键是误导,而我的文章,是详细可行,完全自己整理检验过的,效果杠杠的,如能为你提供一些作用意义,不胜荣幸
VS2019,.NetFramework4.7.2
外部程序:modbus poll,串口调试助手,windows自带的计算器
顶部一个menu控件,menu下添加3个菜单项MenuItem,下面一个整体的splitcontainer控件,控件中左侧放3个button,右侧放一个panel,并让panel在右侧中完全填充停靠,控件命名自己决定
首先生成项目,将会自动创建debug目录,在程序的debug目录下,创建目录,将你的应用程序复制到目录下,
这里的目录结构和层次自己决定,总之就是将你想要启动的外部第三方应用程序复制放在这个debug目录下,总之就是将你想要启动的外部第三方应用程序复制放在这个debug目录下
全部完整代码是:
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);
}
}
}
}
效果相当屌,绝对帅,可不是网上一些傻子的抄袭复制的文章。