当前位置: 首页 > news >正文

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控件 第四章 嵌入外部程序&#xff08;本章&#xff09; 第五章 底部嵌入HwndHost 文章目录 WPF Hwnd窗口互操作系列前言一、如何实现&#xff1f;1、定义属性2、进程嵌入&#xff08;1&…...

【ELK】ELK企业级日志分析系统

搜集日志&#xff1b;日志处理器&#xff1b;索引平台&#xff1b;提供视图化界面&#xff1b;客户端登录 日志收集者&#xff1a;负责监控微服务的日志&#xff0c;并记录 日志存储者&#xff1a;接收日志&#xff0c;写入 日志harbor&#xff1a;负责去连接多个日志收集者&am…...

详细的讲一下java的接口回调

Java的接口回调是一种允许程序在特定事件发生时通知其他对象的机制。这是观察者设计模式的一种实现方式&#xff0c;常用于实现事件监听和异步处理。接口回调允许对象之间进行松耦合的交互&#xff1a;一个对象只知道它可以调用另一个对象的方法&#xff0c;但它不需要知道这个…...

如何将powerpoint(PPT)幻灯片嵌入网页中在线预览、编辑并保存到服务器?

猿大师办公助手不仅可以把微软Office、金山WPS和永中Office的Word文档、Excel表格内嵌到浏览器网页中实现在线预览、编辑保存等操作&#xff0c;还可以把微软Office、金山WPS和永中Office的PPT幻灯片实现网页中在线预览、编辑并保存到服务器。 猿大师办公助手把本机原生Office…...

[Java基础揉碎]日期类

目录 日期类 第一代日期类 第二代日期类 第三代日期类 >前面两代日期类的不足分析 针对以上问题Java在jdk8加入了以下方法 jdk8的时间格式化 时间戳 第三代日期类更多方法 日期类 [知道怎么查,怎么用即可&#xff0c;不用每个方法都背] 第一代日期类 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? &#xff08;1&#xff09;hive是数据仓库建模的工具之一 &#xff08;2&#xff09;可以向hive传入一条交互式的sql,在海量数据中查询分析得到结果的平台 2.Hive简介 Hive本质是将SQL转换为MapReduce的任务进行运算&#xff0c;底层由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个操作&#xff0c;每个操作包含三个整数l, r, c&#xff0c;表示将序列中[l, r]之间的每个数加上c。 请你输出进行完所有操作后的序列。 输入格式 第一行包含两个整数n和m。 第二行包含n个整数&#xff0c;表示整…...

13 指针(上)

指针是 C 语言最重要的概念之一&#xff0c;也是最难理解的概念之一。 指针是C语言的精髓&#xff0c;要想掌握C语言就需要深入地了解指针。 指针类型在考研中用得最多的地方&#xff0c;就是和结构体结合起来构造结点(如链表的结点、二叉树的结点等)。 本章专题脉络 1、指针…...

AI 对话完善【人工智能】

AI 对话【人工智能】 前言版权开源推荐AI 对话v0版本&#xff1a;基础v1版本&#xff1a;对话数据表tag.jsTagController v2版本&#xff1a;回复中textarea.jsChatController v3版本&#xff1a;流式输出chatLast.jsChatController v4版本&#xff1a;多轮对话QianfanUtilChat…...

利用数组储存表格数据

原理以及普通数组储存表格信息 在介绍数组的时候说过&#xff0c;数组能够用来储存任何同类型的数据&#xff0c;这里的意思就表明只要是同一个类型的数组据就可以储存到一个数组中。那么在表格中同一行的数据是否可以储存到同一个数组中呢&#xff1f;答案自然是可以&#xff…...

[数据概念|数据技术]智能合约如何助力数据资产变现

“ 区块链上数据具有高可信度&#xff0c;智能合约将区块链变得更加智能化&#xff0c;以支持企业场景。” 之前鼹鼠哥已经发表了一篇文章&#xff0c;简单介绍了区块链&#xff0c;那么&#xff0c;智能合约又是什么呢&#xff1f;它又是如何助力数据资产变现的呢&#xff1f;…...

JS中的常见二进制数据格式

格式描述用途示例ArrayBuffer固定长度的二进制数据缓冲区&#xff0c;不直接操作具体的数据&#xff0c;而是通过类型数组或DataView对象来读写用于存储和处理大量的二进制数据&#xff0c;如文件、图像等let buffer new ArrayBuffer(16);TypedArray基于ArrayBuffer对象的视图…...

uniapp开发h5端使用video播放mp4格式视频黑屏,但有音频播放解决方案

mp4格式视频有一些谷歌播放视频黑屏&#xff0c;搜狗浏览器可以正常播放 可能和视频的编码格式有关&#xff0c;谷歌只支持h.264编码格式的视频播放 将mp4编码格式修改为h.264即可 转换方法&#xff1a; 如果是自己手动上传文件可以手动转换 如果是后端接口调取的地址就需…...

Hive的分区与排序

一、Hive分区 1.引入&#xff1a; 在大数据中&#xff0c;最常见的一种思想就是分治&#xff0c;我们可以把大的文件切割划分成一个个的小的文件&#xff0c;这样每次操作一个个小的文件就会很容易了&#xff0c;同样的道理&#xff0c;在hive当中也是支持这种思想的&#xff…...

Objective-C学习笔记(内存管理、property参数)4.9

1.引用计数器retainCount&#xff1a;每个对象都有这个属性&#xff0c;默认值为1&#xff0c;记录当前对象有多少人用。 为对象发送一条retain/release消息&#xff0c;对象的引用计数器加/减1&#xff0c;为对象发一条retainCount,得到对象的引用计数器值&#xff0c;当计数器…...

C语言进阶课程学习记录-第29课 - 指针和数组分析(下)

C语言进阶课程学习记录-第29课 - 指针和数组分析&#xff08;下&#xff09; 数组名与指针实验-数组形式转换实验-数组名与指针的差异实验-转化后数组名加一的比较实验-数组名作为函数形参小结 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程&#xff0c;图片全部来源于课…...

一起学习python——基础篇(13)

前言&#xff0c;python编程语言对于我个人来说学习的目的是为了测试。我主要做的是移动端的开发工作&#xff0c;常见的测试主要分为两块&#xff0c;一块为移动端独立的页面功能&#xff0c;另外一块就是和其他人对接工作。 对接内容主要有硬件通信协议、软件接口文档。而涉…...

SOCKS代理概述

在网络技术的广阔领域中&#x1f310;&#xff0c;SOCKS代理是一个核心组件&#xff0c;它在提升在线隐私保护&#x1f6e1;️、实现匿名通信&#x1f3ad;以及突破网络访问限制&#x1f6ab;方面发挥着至关重要的作用。本文旨在深入探讨SOCKS代理的基础&#xff0c;包括其定义…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

rknn toolkit2搭建和推理

安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 &#xff0c;不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源&#xff08;最常用&#xff09; conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...

WEB3全栈开发——面试专业技能点P7前端与链上集成

一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染&#xff08;SSR&#xff09;与静态网站生成&#xff08;SSG&#xff09; 框架&#xff0c;由 Vercel 开发。它简化了构建生产级 React 应用的过程&#xff0c;并内置了很多特性&#xff1a; ✅ 文件系…...

Linux基础开发工具——vim工具

文章目录 vim工具什么是vimvim的多模式和使用vim的基础模式vim的三种基础模式三种模式的初步了解 常用模式的详细讲解插入模式命令模式模式转化光标的移动文本的编辑 底行模式替换模式视图模式总结 使用vim的小技巧vim的配置(了解) vim工具 本文章仍然是继续讲解Linux系统下的…...

大模型真的像人一样“思考”和“理解”吗?​

Yann LeCun 新研究的核心探讨&#xff1a;大语言模型&#xff08;LLM&#xff09;的“理解”和“思考”方式与人类认知的根本差异。 核心问题&#xff1a;大模型真的像人一样“思考”和“理解”吗&#xff1f; 人类的思考方式&#xff1a; 你的大脑是个超级整理师。面对海量信…...

Ubantu-Docker配置最新镜像源250605

尝试其他镜像加速器 阿里云镜像加速器&#xff1a;登录阿里云&#xff0c;进入容器镜像服务获取专属加速器地址。毫秒镜像&#xff1a;https://docker.1ms.run。DockerHub镜像加速器&#xff1a;https://docker.xuanyuan.me。Docker Hub 镜像加速服务&#xff1a;https://dock…...