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>
效果预览

总结
以上就是今天要讲的内容,嵌入外部程序还是相对比较容易实现的,而且也有一定的使用场景。创建进程,并能获取到进程的主窗口句柄即可。另外要注意的是管理子进程的退出,其他都问题不大。
相关文章:
C# wpf 嵌入外部程序
WPF Hwnd窗口互操作系列 第一章 嵌入Hwnd窗口 第二章 嵌入WinForm控件 第三章 嵌入WPF控件 第四章 嵌入外部程序(本章) 第五章 底部嵌入HwndHost 文章目录 WPF Hwnd窗口互操作系列前言一、如何实现?1、定义属性2、进程嵌入(1&…...
【ELK】ELK企业级日志分析系统
搜集日志;日志处理器;索引平台;提供视图化界面;客户端登录 日志收集者:负责监控微服务的日志,并记录 日志存储者:接收日志,写入 日志harbor:负责去连接多个日志收集者&am…...
详细的讲一下java的接口回调
Java的接口回调是一种允许程序在特定事件发生时通知其他对象的机制。这是观察者设计模式的一种实现方式,常用于实现事件监听和异步处理。接口回调允许对象之间进行松耦合的交互:一个对象只知道它可以调用另一个对象的方法,但它不需要知道这个…...
如何将powerpoint(PPT)幻灯片嵌入网页中在线预览、编辑并保存到服务器?
猿大师办公助手不仅可以把微软Office、金山WPS和永中Office的Word文档、Excel表格内嵌到浏览器网页中实现在线预览、编辑保存等操作,还可以把微软Office、金山WPS和永中Office的PPT幻灯片实现网页中在线预览、编辑并保存到服务器。 猿大师办公助手把本机原生Office…...
[Java基础揉碎]日期类
目录 日期类 第一代日期类 第二代日期类 第三代日期类 >前面两代日期类的不足分析 针对以上问题Java在jdk8加入了以下方法 jdk8的时间格式化 时间戳 第三代日期类更多方法 日期类 [知道怎么查,怎么用即可,不用每个方法都背] 第一代日期类 1) Date: …...
4.10作业
//.h文件#ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimerEvent> //定时器事件类 #include <QTime> //时间类 #include <QString> #include <QPushButton> //按钮类 #include <QLabel> //标签类 #include <QT…...
Hive概述与基本操作
一、Hive基本概念 1.什么是hive? (1)hive是数据仓库建模的工具之一 (2)可以向hive传入一条交互式的sql,在海量数据中查询分析得到结果的平台 2.Hive简介 Hive本质是将SQL转换为MapReduce的任务进行运算,底层由HDFS…...
安装 FFmpeg
安装 FFmpeg 1. Install FFmpeg On Ubuntu2. Install FFmpeg On Ubuntu 16.042.1. First add the repository2.2. Update the newly added repository2.3. Now install the ffmpeg2.4. For opening the ffmpeg for that type ffpmeg on the terminal 3. Uninstall ffmpegRefere…...
18、差分
差分 题目描述 输入一个长度为n的整数序列。 接下来输入m个操作,每个操作包含三个整数l, r, c,表示将序列中[l, r]之间的每个数加上c。 请你输出进行完所有操作后的序列。 输入格式 第一行包含两个整数n和m。 第二行包含n个整数,表示整…...
13 指针(上)
指针是 C 语言最重要的概念之一,也是最难理解的概念之一。 指针是C语言的精髓,要想掌握C语言就需要深入地了解指针。 指针类型在考研中用得最多的地方,就是和结构体结合起来构造结点(如链表的结点、二叉树的结点等)。 本章专题脉络 1、指针…...
AI 对话完善【人工智能】
AI 对话【人工智能】 前言版权开源推荐AI 对话v0版本:基础v1版本:对话数据表tag.jsTagController v2版本:回复中textarea.jsChatController v3版本:流式输出chatLast.jsChatController v4版本:多轮对话QianfanUtilChat…...
利用数组储存表格数据
原理以及普通数组储存表格信息 在介绍数组的时候说过,数组能够用来储存任何同类型的数据,这里的意思就表明只要是同一个类型的数组据就可以储存到一个数组中。那么在表格中同一行的数据是否可以储存到同一个数组中呢?答案自然是可以ÿ…...
[数据概念|数据技术]智能合约如何助力数据资产变现
“ 区块链上数据具有高可信度,智能合约将区块链变得更加智能化,以支持企业场景。” 之前鼹鼠哥已经发表了一篇文章,简单介绍了区块链,那么,智能合约又是什么呢?它又是如何助力数据资产变现的呢?…...
JS中的常见二进制数据格式
格式描述用途示例ArrayBuffer固定长度的二进制数据缓冲区,不直接操作具体的数据,而是通过类型数组或DataView对象来读写用于存储和处理大量的二进制数据,如文件、图像等let buffer new ArrayBuffer(16);TypedArray基于ArrayBuffer对象的视图…...
uniapp开发h5端使用video播放mp4格式视频黑屏,但有音频播放解决方案
mp4格式视频有一些谷歌播放视频黑屏,搜狗浏览器可以正常播放 可能和视频的编码格式有关,谷歌只支持h.264编码格式的视频播放 将mp4编码格式修改为h.264即可 转换方法: 如果是自己手动上传文件可以手动转换 如果是后端接口调取的地址就需…...
Hive的分区与排序
一、Hive分区 1.引入: 在大数据中,最常见的一种思想就是分治,我们可以把大的文件切割划分成一个个的小的文件,这样每次操作一个个小的文件就会很容易了,同样的道理,在hive当中也是支持这种思想的ÿ…...
Objective-C学习笔记(内存管理、property参数)4.9
1.引用计数器retainCount:每个对象都有这个属性,默认值为1,记录当前对象有多少人用。 为对象发送一条retain/release消息,对象的引用计数器加/减1,为对象发一条retainCount,得到对象的引用计数器值,当计数器…...
C语言进阶课程学习记录-第29课 - 指针和数组分析(下)
C语言进阶课程学习记录-第29课 - 指针和数组分析(下) 数组名与指针实验-数组形式转换实验-数组名与指针的差异实验-转化后数组名加一的比较实验-数组名作为函数形参小结 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程,图片全部来源于课…...
一起学习python——基础篇(13)
前言,python编程语言对于我个人来说学习的目的是为了测试。我主要做的是移动端的开发工作,常见的测试主要分为两块,一块为移动端独立的页面功能,另外一块就是和其他人对接工作。 对接内容主要有硬件通信协议、软件接口文档。而涉…...
SOCKS代理概述
在网络技术的广阔领域中🌐,SOCKS代理是一个核心组件,它在提升在线隐私保护🛡️、实现匿名通信🎭以及突破网络访问限制🚫方面发挥着至关重要的作用。本文旨在深入探讨SOCKS代理的基础,包括其定义…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...
高考志愿填报管理系统---开发介绍
高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发,采用现代化的Web技术,为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## 📋 系统概述 ### 🎯 系统定…...
