C# wpf 嵌入外部程序

WPF Hwnd窗口互操作系列

第一章 嵌入Hwnd窗口
第二章 嵌入WinForm控件
第三章 嵌入WPF控件
第四章 嵌入外部程序(本章)
第五章 底部嵌入HwndHost


文章目录

  • WPF Hwnd窗口互操作系列
  • 前言
  • 一、如何实现?
    • 1、定义属性
    • 2、进程嵌入
      • (1)启动进程
      • (2)、进程加入作业对象
      • (3)、获取主窗口句柄
    • 3、销毁进程
  • 二、完整代码
  • 三、使用示例
    • 1、嵌入ffplay.exe
  • 总结


前言

实现嵌入各种窗口控件后,其实还会有一种需求:嵌入外部程序,我们有时可能需要嵌入一个浏览器或者或者播放器等一些已有的程序,其嵌入原理也和前面差不多,只要能获取进程的主窗口句柄,然后将窗口嵌入。


一、如何实现?

1、定义属性

定义一个依赖属性,提供给xaml设置进程运行的命令行

public class AppHost : HwndHost
{
    /// <summary>
    /// 进程运行的命令行
    /// </summary>
    public string Cmdline
    {
        get { return (string)GetValue(CmdlineProperty); }
        set { SetValue(CmdlineProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Cmdline.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CmdlineProperty =
        DependencyProperty.Register("Cmdline", typeof(string), typeof(AppHost), new PropertyMetadata(""));
}        

2、进程嵌入

在下列方法中进行进程嵌入,具体操作如下列步骤。

protected override HandleRef BuildWindowCore(HandleRef hwndParent)

(1)启动进程

var cmds = Cmdline.Split(" ", 2);
Process? _process;
_process.StartInfo.FileName = cmds.First();
_process.StartInfo.Arguments = cmds.Last();
_process.StartInfo.UseShellExecute = false;
_process.StartInfo.CreateNoWindow = true;
_process.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
_process.Start();

(2)、进程加入作业对象

这个步骤是用于管理进程,确保《子进程跟随主进程关闭》。

static Job _job = new Job();
_job.AddProcess(_process.Handle);

(3)、获取主窗口句柄

下列提供的是简单获取主窗口句柄的方法。通过延时等待的方式获取。需要精确时间获取主窗口句柄则可以使用钩子,在子进程窗口创建事件中获取句柄。

for (int i = 0; i < 200 && _process.MainWindowHandle == 0; i++) Thread.Sleep(5);
if (_process.MainWindowHandle == 0)
{
    throw new Exception("process no window");
}
return new HandleRef(this, Handle);

3、销毁进程

protected override void DestroyWindowCore(HandleRef hwnd)
{
    _process?.Kill();
    _process?.Dispose();
    _process = null;
}

二、完整代码

其中Job对象在《子进程跟随主进程关闭》中。
AppHost.cs

using JobManagement;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using Process = System.Diagnostics.Process;
using TextBox = System.Windows.Controls.TextBox;
using Thread = System.Threading.Thread;

namespace WpfHwndElement
{
    /// <summary>
    /// 需要手动dispose此控件。
    /// </summary>
    public class AppHost : HwndHost
    {
        static Job _job = new Job();
        Process? _process;
        /// <summary>
        /// 进程运行的命令行
        /// </summary>
        public string Cmdline
        {
            get { return (string)GetValue(CmdlineProperty); }
            set { SetValue(CmdlineProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Cmdline.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CmdlineProperty =
            DependencyProperty.Register("Cmdline", typeof(string), typeof(AppHost), new PropertyMetadata(""));

        new public IntPtr Handle
        {
            get { return (IntPtr)GetValue(HandleProperty); }
            private set { SetValue(HandleProperty, value); }
        }
        // Using a DependencyProperty as the backing store for Hwnd.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HandleProperty =
            DependencyProperty.Register("Handle", typeof(IntPtr), typeof(NativeHost), new PropertyMetadata(IntPtr.Zero));
        protected override HandleRef BuildWindowCore(HandleRef hwndParent)
        {
            try
            {
                if (DesignerProperties.GetIsInDesignMode(this)) throw new Exception("design mode won't show app");
                var cmds = Cmdline.Split(" ", 2);
                _process = new Process();
                _process.StartInfo.FileName = cmds.First();
                _process.StartInfo.Arguments = cmds.Length > 1 ? cmds.Last() : "";
                _process.StartInfo.UseShellExecute = false;
                _process.StartInfo.CreateNoWindow = true;
                _process.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
                _process.Start();
                _job.AddProcess(_process.Handle);
                for (int i = 0; i < 200 && _process.MainWindowHandle == 0; i++) Thread.Sleep(5);
                if (_process.MainWindowHandle == 0)
                {
                    throw new Exception("process no window");
                }
                Handle = _process.MainWindowHandle;
                var wndStyle = GetWindowLong(Handle, GWL_STYLE);
                wndStyle &= ~WS_THICKFRAME;
                wndStyle &= ~WS_CAPTION;
                SetWindowLong(Handle, GWL_STYLE, wndStyle | WS_CHILD);
                SetParent(Handle, hwndParent.Handle);
            }
            catch (Exception ex)
            {
                var window = new Window() { Width = 0, Height = 0, ResizeMode = ResizeMode.NoResize, WindowStyle = WindowStyle.None, Content = new TextBox() { IsReadOnly = true, Text = ex.Message + " " + ex.StackTrace, TextWrapping = TextWrapping.Wrap } };
                var hwnd = new WindowInteropHelper(window).EnsureHandle();
                window.Show();
                SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_CHILD);
                SetParent(hwnd, hwndParent.Handle);
                Handle = hwnd;
            }
            return new HandleRef(this, Handle);
        }
        protected override void DestroyWindowCore(HandleRef hwnd)
        {
            var window = HwndSource.FromHwnd(hwnd.Handle)?.RootVisual as Window;
            window?.Close();
            _process?.Kill();
            _process?.Dispose();
            _process = null;
        }
        const int WS_CAPTION = 0x00C00000;
        const int WS_THICKFRAME = 0x00040000;
        const int WS_CHILD = 0x40000000;
        const int GWL_STYLE = (-16);
        [DllImport("user32.dll", EntryPoint = "GetWindowLongW")]
        static extern int GetWindowLong(IntPtr hwnd, int nIndex);
        [DllImport("user32.dll", EntryPoint = "SetWindowLongW")]
        static extern int SetWindowLong(IntPtr hwnd, int nIndex, int dwNewLong);
        [DllImport("user32.dll")]
        public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
    }
}

三、使用示例

1、嵌入ffplay.exe

MainWindow.xaml

<Window x:Class="WpfHwndElement.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfHwndElement"
        mc:Ignorable="d"
        Title="MainWindow" Height="360" Width="640"       
        >
    <Grid>
        <local:AppHost Cmdline="ffplay" Width="200" Height="200"></local:AppHost>
    </Grid>
</Window>

效果预览
在这里插入图片描述


总结

以上就是今天要讲的内容,嵌入外部程序还是相对比较容易实现的,而且也有一定的使用场景。创建进程,并能获取到进程的主窗口句柄即可。另外要注意的是管理子进程的退出,其他都问题不大。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/524529.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Windows11配置VUE开发环境

目录 一、按照nodejs二、命令安装npm cache clean --forcenpm install -g vue/clinpm install npm -gnpm install webpacknpm install vue-cli -g与npm install -g vue/cli区别npm install -g cnpm --registryhttps://registry.npm.taobao.orgnpm i yarn -g --verbosenpm i -g …

全面解析十七种数据分析方法,具象数据分析思维

一、介绍 在当今数据驱动的商业环境中&#xff0c;数据分析已经成为了企业获取竞争优势的关键工具。无论是为了优化运营效率&#xff0c;提高客户满意度&#xff0c;还是推动产品创新&#xff0c;企业都需要通过分析大量数据来做出明智的决策。数据分析方法多种多样&#xff0c…

计算机网络-文件传输及IP协议——沐雨先生

实验内容 编写请求文件的客户Java应用程序编写响应文件请求的服务器Java应用程序利用Wireshark查看和分析IP包 基本要求 使用Java语言建立请求文件的客户应用程序使用Java语言建立响应文件请求的服务器应用程序了解IP协议的工作过程了解IP包首部各字段及含义 对Java应用程序…

机器学习——模型融合:平均法

机器学习——模型融合&#xff1a;平均法 在机器学习领域&#xff0c;模型融合是一种通过结合多个基本模型的预测结果来提高整体模型性能的技术。模型融合技术通常能够降低预测的方差&#xff0c;提高模型的鲁棒性&#xff0c;并在一定程度上提高预测的准确性。本文将重点介绍…

数据结构初阶:栈和队列

栈 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。 栈中的数据元素遵守后进先出 LIFO &#xff08; Last In First Out &#xff09;的原则。…

腾讯云4核8G服务器12M带宽646元1年零3个月,4C8G使用场景说明

腾讯云4核8G服务器多少钱&#xff1f;腾讯云4核8G轻量应用服务器12M带宽租用价格646元15个月&#xff0c;活动页面 txybk.com/go/txy 活动链接打开如下图所示&#xff1a; 腾讯云4核8G服务器优惠价格 这台4核8G服务器是轻量应用服务器&#xff0c;详细配置为&#xff1a;轻量4核…

hive图形化客户端工具

hive准备 创建测试数据 以root用户登录&#xff0c;使用hive命令启动hive。 创建库 create database testhivedb; 创建表 create table testhivedb.testhivetable( id int ,name string ); 插入数据 insert into testhivedb.testhivetable values (1,cc); insert into…

《债务与国家的崛起》西方民主制度的金融起源 - 三余书屋 3ysw.net

债务与国家的崛起&#xff1a;西方民主制度的金融起源 你好&#xff0c;今天我们来聊聊由英国知名经济与金融历史学家詹姆斯麦克唐纳所著的《债务与国家的崛起》这本书。19世纪世界历史上发生了一次巨变&#xff0c;即“大分流”。当时西方通过工业革命实现了科技和经济的飞速…

为什么苹果 Mac 电脑需要使用清理软件?

尽管 Apple Mac 电脑因其卓越的性能、简洁高效的 macOS 操作系统及独特的美学设计备受全球用户青睐&#xff0c;但任何电子设备在长期使用后都难以避免面临系统资源日渐累积的问题。其中一个重要维护需求在于&#xff0c;随着使用时间的增长&#xff0c;Mac电脑可能会由于系统垃…

xilinx 7系列fpga上电配置

一、前言 Xilinx FPGA通过加载比特流到内部存储单元来进行配置。 Xilinx FPGA存在两种数据配置路径&#xff0c;一种是满足最小引脚需求的串行路径&#xff0c;一种是可用8位、16位或32位来连接到行业的高性能通用接口&#xff0c;如处理器&#xff0c;8位或者16位并行的闪存…

测试开发:从0到1学习如何测试API网关

日常工作中&#xff0c;难免会遇到临危受命的情况&#xff0c;虽然没有这么夸张&#xff0c;但是也可能会接到一个陌生的任务&#xff0c;也许只是对这个概念有所耳闻。也许这个时候会感到一丝的焦虑&#xff0c;生怕没法完成领导交给的测试任务。其实也没有必要那么紧张&#…

【微服务】面试题(一)

最近进行了一些面试&#xff0c;这几个问题分享给大家 一、分别介绍一下微服务、分布式以及两者的区别 微服务&#xff08;Microservices&#xff09;和分布式系统&#xff08;Distributed Systems&#xff09;是两种不同的软件架构风格&#xff0c;虽然它们之间有些重叠&#…

南京观海微电子---Vitis HLS设计流程(实例演示)——Vitis HLS教程

1. 前言 课时2我们介绍了Vitis HLS的设计流程&#xff0c;如下图所示&#xff1a; 算法或软件的设计和仿真都基于C/C&#xff0c;通过HLS平台导出打包好的IP RTL代码&#xff0c;最后将该打包的IP加入到主工程使用。 本课时&#xff0c;我们通过一个具体的实例&#xff0c;演示…

Kibana管理ES生命周期

希望通过Kibana界面管理ES索引的生命周期 版本&#xff1a;7.15.2 创建索引模板 创建索引模板方便匹配索引&#xff0c;对匹配到的一批索引采用同一套生命周期管理策略&#xff0c;例如开发环境的所有索引以dev-开头&#xff0c;可以创建样式为dev-*的索引模板以匹配开发环境…

【服务器uwsgi + flask + nginx的搭建】

目录 服务器uwsgi flask nginx的搭建1. 安装必要的软件2. 启动nginx服务3. 测试Nginx4. 配置uwsgi和flask5. 配置nginx 服务器uwsgi flask nginx的搭建 1. 安装必要的软件 安装Python、uWSGI、Flask 和 Nginx。 # Ubuntu 安装命令 sudo apt-get update sudo apt-get ins…

海外媒体宣发,穿透与世界的交流 - “保姆级”教程 - 大舍传媒

1. 引言 在当今高度信息化的世界&#xff0c;境外媒体宣发已经成为企业、品牌和政府机构推广自身形象、扩大影响力的重要手段。如何在国际舞台上有效传播信息&#xff0c;提高国际知名度&#xff0c;成为了许多组织面临的重要课题。大舍传媒凭借多年的境外媒体宣发经验&#x…

第六篇: 3.5 性能效果 (Performance)- IAB/MRC及《增强现实广告效果测量指南1.0》

​​​​​​​ 翻译计划 第一篇概述—IAB与MRC及《增强现实广告效果测量指南》之目录、适用范围及术语第二篇 广告效果测量定义和其他矩阵之- 3.1 广告印象&#xff08;AD Impression&#xff09;第三篇 广告效果测量定义和其他矩阵之- 3.2 可见性 &#xff08;Viewability…

Goingpub国自然基金-免费查询

可进行年份、学部、项目类别等检索&#xff0c;支持生成主题词汇总分析报告。 最最最关键&#xff0c;免费&#xff0c;只需要你注册登录一下&#xff0c;防止被爬虫侵扰。 界面简单&#xff0c;实用&#xff0c;支持模糊搜索&#xff0c;包含最新2023年数据&#xff0c;共56…

34-4 CSRF漏洞 - CSRF跨站点请求伪造

一、漏洞定义 CSRF(跨站请求伪造)是一种客户端攻击,又称为“一键式攻击”。该漏洞利用了Web应用程序与受害用户之间的信任关系,通过滥用同源策略,使受害者在不知情的情况下代表攻击者执行操作。与XSS攻击不同,XSS利用用户对特定网站的信任,而CSRF则利用了网站对用户网页…

yolov9直接调用zed相机实现三维测距(python)

yolov9直接调用zed相机实现三维测距&#xff08;python&#xff09; 1. 相关配置2. 相关代码2.1 相机设置2.2 测距模块2.2 实验结果 相关链接 此项目直接调用zed相机实现三维测距&#xff0c;无需标定&#xff0c;相关内容如下&#xff1a; 1. yolov4直接调用zed相机实现三维测…