WinForm Panel嵌入Exe窗体并实现窗口大小自适应变化

流程:由于证书的问题,外部exe会在进入最终界面之前弹出两个对话框,所以需要点击"嵌入SA"两次。第一次启动exe,在手动点击弹出的两个无用对话框后出现最终界面,再点击一次实现嵌入。

思路:遍历电脑所有进程,通过窗口标题查找对应的进程。如果没找到,说明窗口已存在,直接使用该找到的进程进行嵌入;否则,先利用exe路径打开开启进程。另外,还要在程序退出时关闭进程,这里是在构造函数中实现了该功能,需要检查进程是否为空和是否已经退出,如果进程在则kill掉进程。

界面:要填充的parent control控件为panel,其dock属性为Fill,嵌入的窗口可以根据panel尺寸大小而变动。主要也是参考网上的一个帖子,然后加上了另外一个帖子的窗口尺寸自适应变化代码,最终界面效果如下图。
在这里插入图片描述
代码实现

    public class WinfromUtil
    {
        Process                            m_SAProcess;//SA进程
        bool                               m_isEmbeded = false;//是否已经嵌入
        Control                            m_parentControl = null;


        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);

        ~WinfromUtil()
        {
            if (m_SAProcess != null)
            {
                if (!m_SAProcess.HasExited)
                    m_SAProcess.Kill();
            }
        }

        public void exbedExistingWindow(string mainWindowTitle, Control parentControl)
        {
            Process[] pro = Process.GetProcesses();//获取已开启的所有进程
            for (int i = 0; i < pro.Length; i++)
            { 
                string title = pro[i].MainWindowTitle;
                if(title.Contains(mainWindowTitle))
                {
                    MessageBox.Show(title, "进程" + i.ToString());
                    SetParent(pro[i].MainWindowHandle, parentControl.Handle);
                    ShowWindow(pro[i].MainWindowHandle, 3);
                    m_SAProcess = pro[i];
                }
                    
            }
        }

        public bool embedExternalWindow(string exePath, string mainWindowTitle, Control parentControl)
        {
            //遍历所有电脑进程,通过窗口标题找到对应的进程
            Process[] pro = Process.GetProcesses();//获取已开启的所有进程
            int saProcessIndex = -1;
            for (int i = 0; i < pro.Length; i++)
            {
                if (pro[i].MainWindowTitle.Contains(mainWindowTitle))
                {
                    saProcessIndex = i;
                    break;
                }
                    
            }

            if (saProcessIndex == -1)//sa没启动的话就启动exe
            {
                string param = "";
                Process process = new Process();
                ProcessStartInfo startInfo = new ProcessStartInfo(exePath, param);
                startInfo.FileName = exePath;
                startInfo.UseShellExecute = false;
                startInfo.RedirectStandardOutput = false;
                startInfo.WindowStyle = ProcessWindowStyle.Minimized;//为了美观,启动的时候最小化程序
                process.StartInfo = startInfo;
                process.Start();
                // Wait for process to be created and enter idle condition
                process.WaitForInputIdle();

                return false;

            }else if(saProcessIndex != -1)//如果启动了,就进行嵌入
            {
                if (m_isEmbeded)
                    return true;

                m_SAProcess = pro[saProcessIndex];
                
                IntPtr mainHandle = m_SAProcess.MainWindowHandle;//通过进程得到对应的句柄

                
                SetParent(m_SAProcess.MainWindowHandle, parentControl.Handle);
                ShowWindow(m_SAProcess.MainWindowHandle, (int)ProcessWindowStyle.Maximized);//3
                MoveWindow(m_SAProcess.MainWindowHandle, 0, 0, parentControl.Width, parentControl.Height, true);

                m_parentControl = parentControl;
                m_parentControl.SizeChanged += Control_SizeChanged;

                m_isEmbeded = true;
                return true;
            }
            else
            {
                return false;
            }



        }


        /// <summary>
        /// 获取窗体的句柄函数
        /// </summary>
        /// <param name="lpClassName">窗口类名</param>
        /// <param name="lpWindowName">窗口标题名</param>
        /// <returns>返回句柄</returns>
            [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("User32.dll ", EntryPoint = "SetParent")]
        private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

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


        /// <summary>
        /// 【函数类型:工具类对外接口】
        /// 【函数功能:加载外部exe程序到容器】
        /// 【创建作者:LZHRyan】
        /// 【创建时间:2018-4-5 13:52:24】
        /// </summary>
        /// <param name="exePath">exe程序路径</param>
        /// <param name="param">exe初始化参数</param>
        /// <param name="parentControl">依赖容器</param>
        /// <param name="formTitle">主窗体标题</param>
        /// <param name="canReLoad">是否允许重复运行程序</param>
        public void ExeLoader(string exePath, string param, Control parentControl, string formTitle, bool canReLoad)
        {
            if (exePath.Contains(".exe") || exePath.Contains(".EXE"))
            {
                if (File.Exists(exePath))
                {
                    try
                    {
                        Process process = new Process();
                        ProcessStartInfo startInfo = new ProcessStartInfo(exePath, param);
                        startInfo.FileName = exePath;
                        startInfo.UseShellExecute = false;
                        startInfo.RedirectStandardOutput = false;
                        startInfo.WindowStyle = ProcessWindowStyle.Minimized;

                        process.StartInfo = startInfo;
                        IntPtr mainHandle = FindWindow(null, formTitle);
                        process.Start();
                        int count = 0;
                        while (count < 20 * 30 && mainHandle == IntPtr.Zero)
                        {
                            count++;
                            Thread.Sleep(100);
                            mainHandle = FindWindow(null, formTitle);
                        }
                        //不允许重复启动,如果在这里限制了不能多启动相同进程,则调用的进程不能做相同的限制
                        if (!canReLoad && Process.GetProcessesByName(process.ProcessName).Length > 1)
                        {
                            //杀掉进程
                            process.Kill();
                            return;
                        }
                        else
                        {
                            SetParent(process.MainWindowHandle, parentControl.Handle);
                            ShowWindow(process.MainWindowHandle, 3);
                        }

                        MessageBox.Show("退出", "提示");
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, "异常", MessageBoxButtons.OK, MessageBoxIcon.Error);

                    }

                }
                else
                {
                    string content = "未能找到文件:" + exePath;
                    string title = "错误提示";
                    MessageBox.Show(content, title, MessageBoxButtons.OK, MessageBoxIcon.Error);

                }
            }
            else
            {
                string content = "文件格式不是可执行程序:" + exePath;
                string title = "错误提示";
                MessageBox.Show(content, title, MessageBoxButtons.OK, MessageBoxIcon.Error);   
            }
        }


        private void Control_SizeChanged(object sender, EventArgs e)
        {
            if (m_SAProcess == null || !m_isEmbeded)
                return;

            if (m_SAProcess.MainWindowHandle != IntPtr.Zero && m_parentControl != null)
                MoveWindow(m_SAProcess.MainWindowHandle, 0, 0, m_parentControl.Width, m_parentControl.Height, true);
        }

    }

使用

            string SAPath = "D:\\Program Files\\SpatialAnalyzer 2018.01.12_35218\\Spatial Analyzer.exe";            
            string title = "无标题 - SpatialAnalyzer";
            m_externalWindow = new WinfromUtil();
            m_externalWindow.embedExternalWindow(SAPath, title, panel_exmbedSA);

嵌入后的外部窗体悬浮
嵌入外部进程窗体后,可能想让嵌入的窗体悬浮,独立出去。既然嵌入窗体是给外部窗体一个parent,那如果该parent为null,那就是独立出去了,用到的函数为SetParent。代码如下:

        //悬浮窗口,即不嵌入
        public void floatEmbededWindow()
        {
            if (m_SAProcess == null)
                return;
            SetParent(m_SAProcess.MainWindowHandle, IntPtr.Zero);//m_SAProcess是外部窗口进程
            m_isEmbeded = false;
        }
  • 0
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值