C# 内嵌窗体-捕捉进程外的程序窗体到自有控件中显示

本文是实现窗体内嵌,如果需要实现类似程序加壳功能,嵌入外部程序并运行,可参考本人发表的文章:https://blog.csdn.net/lzl_li/article/details/117026469

近期发现ffplay很好强大,但没有图形控制界面,就想对ffplay进行简单包装,程序运行ffplay然后将ffplay显示的窗体拉入自己的控件上,实现播放器功能。[程序已完成]

在此过程中,本人建立了一个类,通过窗体标题字符串查找目标窗体或通过进程获取进程的主窗体,然后将目标窗体内嵌到自有控件中显示,在此分享给大家。(封装ffplay的程序没有在本文介绍,因为封装ffplay还涉及一些数据分析及控制)

补充说明:通过SetParent内嵌窗体成功后,后台通过GetParent获取内嵌窗体的父窗体句柄还是0,而且内嵌窗体进程的MainWindowHandle的值也变成0

  • 内嵌外部窗体主要使用SetParent函数,函数中的第1个参数是我们的目标窗体句柄,第2个参数是要设置的父控件句柄。
  • 目标窗体句柄可用EnumWindows函数枚举系统里的所有顶层窗体,结合GetWindowText函数查找窗体标题字符串获取我们想要的目标窗体句柄,或者使用GetProcessHandleFromHwnd从窗体句柄获取所在进程的句柄,再使用GetProcessId将进程句柄转化为进程ID,通过进程ID识别是否为我们要找的窗体。

主要代码如下(全部源代码下载):


        /// <summary>
        /// 开始通过标题关键字查找并捕捉窗体(找到符合条件的第一个窗体之后中断)
        /// </summary>
        /// <returns>捕获是否成功</returns>
        public bool Start()
        {
            System.Diagnostics.Process[] pros = System.Diagnostics.Process.GetProcesses();
            foreach (System.Diagnostics.Process p in pros)
            {
                if (p.MainWindowTitle.Contains(titleString))
                {
                    targetForm = p.MainWindowHandle;//将找到的窗体句柄赋值给targetForm
                    pullForm(p);//将窗体拉入设定的控件中,传递p主要用于监测进程退出事件
                    break;
                }
            }

            /* 方法二:调用API获取
            CallBack cback = new CallBack(this.FindControl);
            int r=EnumWindows(cback, 0);
            pullForm();
            //*/
            if (targetForm.Equals(IntPtr.Zero))
                return false;
            else
                return true;
        }
        /// <summary>
        /// 通过进程ID捕捉进程主窗体
        /// </summary>
        /// <param name="processID">进程ID</param>
        /// <returns>捕获是否成功</returns>
        public bool Start(int processID)
        {
            System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(processID);
            targetForm = p.MainWindowHandle;//将找到的窗体句柄赋值给targetForm
            pullForm(p);//将窗体拉入设定的控件中,传递p主要用于监测进程退出事件

            if (targetForm.Equals(IntPtr.Zero))
                return false;
            else
                return true;
        }
        
        /// <summary>
        /// API函数EnumWindows调用的委托函数实现
        /// </summary>
        /// <param name="hwnd"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        private bool FindControl(IntPtr hwnd, int lParam)
        {
            IntPtr pHwnd;
            pHwnd = GetParent(hwnd);

            //if (IsWindowVisible(hwnd) == 1)
            if (pHwnd == IntPtr.Zero && IsWindowVisible(hwnd) == 1)
            {
                StringBuilder sb = new StringBuilder(512);
                GetWindowText(hwnd, sb, sb.Capacity);
                if (sb.ToString().Contains(titleString))
                {
                    targetForm = hwnd;
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 捕获窗体(前提是目标窗体targetForm已经赋值)
        /// </summary>
        private void pullForm()
        {
            if (targetForm == IntPtr.Zero)
                return;
            bool ok = false;
            IntPtr pHandle = GetProcessHandleFromHwnd(targetForm);
            int pid = GetProcessId(pHandle);
            System.Diagnostics.Process[] pros = System.Diagnostics.Process.GetProcesses();
            foreach (System.Diagnostics.Process p in pros)
            {
                try
                {
                    //if (p.Handle == pHandle)//p.Handle拒绝访问
                    if (p.Id == pid)//找到窗体所在进程
                    {
                        pullForm(p);
                        ok = true;
                        break;
                    }
                }
                catch { }
            }
            if (ok == false)
                pullForm(null);
        }

        /// <summary>
        /// 捕捉窗体(前提是目标窗体targetForm已经赋值)
        /// </summary>
        /// <param name="p">窗体所属进程</param>
        private void pullForm(System.Diagnostics.Process p)
        {
            if (targetForm == IntPtr.Zero)
                return;
            IntPtr curParent = GetParent(targetForm);
            process = p;

            RECT rect = new RECT();
            bool r = GetWindowRect(targetForm, ref rect);//获取当前位置大小信息,便于后续恢复状态
            oldState = new FormState(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
            SetParent(targetForm, parent);//设置新的父控制(捕捉到自己想要的控件上),要注意的是设置成功后通过GetParent获取内嵌窗体的父窗体句柄还是0
            Resize();//调整大小到新父控件大小
            threadWaitExit = new System.Threading.Thread(threadWaitAppExit);
            threadWaitExit.Start(p);//开启线程:监测进程结束
        }

完整源代码下载

另外,程序加壳功能可参考:https://blog.csdn.net/lzl_li/article/details/117026469

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lzl_li

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

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

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

打赏作者

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

抵扣说明:

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

余额充值