C# wpf 实现底部嵌入HwndHost

WPF Hwnd窗口互操作系列

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


文章目录

  • WPF Hwnd窗口互操作系列
  • 前言
  • 一、如何实现?
    • 1、底部创建窗口
      • (1)、创建透明窗口
      • (2)、监控顶部窗口事件
      • (3)、窗口保持在底部
    • 2、HwndHost加入底部窗口
    • 3、Clip穿透顶部窗口
    • 4、WPF控件放在装饰层
  • 二、完整代码
    • 1、对象定义
    • 2、完整代码
  • 三、使用示例
    • 1、嵌入Winform控件
    • 2、显示视频
    • 3、圆角矩形视频
    • 4、拖动位置大小
  • 总结


前言

前面三章内容是笔者基于本章内容研发过程中的附带产物,但是意外的发现第三章可嵌入wpf控件后,本章的意义就变得不那么大了。本章讲述如何从底部嵌入hwnd窗口,以此来做到嵌入窗口不覆盖wpf控件的效果,这种实现思路参考了flutter的一个插件flutter_native_view,其内部实现就用了这种方式。对于wpf实现会复杂一些,因为提供自绘没有BlendMode之类的东西,无法直接消除底部画面,能够使用的方式是Clip,这种方式限制比较多。不过最终还是实现了功能。


一、如何实现?

1、底部创建窗口

(1)、创建透明窗口

 _backgroundWindow = new Window() { WindowStyle = WindowStyle.None, ResizeMode = ResizeMode.NoResize, Focusable = false, Width = 0, Height = 0, ShowInTaskbar = false, ShowActivated = false, Background = Brushes.Transparent, Content = new Grid(), AllowsTransparency = true, };_backgroundHandle = (new WindowInteropHelper(_backgroundWindow)).EnsureHandle();

(2)、监控顶部窗口事件

添加hook监控上层窗口的事件

HwndSource.FromHwnd(_forgroundHandle).AddHook(new HwndSourceHook(WndProc));

(3)、窗口保持在底部

监控相关事件保证窗口始终贴在下面。

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{switch (msg){case WM_ACTIVATE:case WM_MOVE:case WM_SIZE:RECT rect;GetWindowRect(_forgroundHandle, out rect);SetWindowPos(_backgroundHandle, _forgroundHandle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE);break;}return IntPtr.Zero;
}

2、HwndHost加入底部窗口

需要嵌入的hwnd窗口,直接嵌入到底部窗口。下列代码中Content是HwndHost控件,在xaml中设置。在cs代码中直接将其添加到底部窗口中。

[ContentProperty("Content")]
public class HwndHostBottomEmbbeder : FrameworkElement
{public HwndHost Content{get { return (HwndHost)GetValue(HostProperty); }set { SetValue(HostProperty, value); }}
}
var grid = _backgroundWindow.Content as Grid;
grid.Children.Add(Content);

3、Clip穿透顶部窗口

和其他嵌入方式一样,需要先继承HwndHost。clip原理参考《C# wpf利用Clip属性实现截屏框》

//顶部窗口句柄
IntPtr _forgroundHandle = IntPtr.Zero;
//底部窗口句柄
IntPtr _backgroundHandle = IntPtr.Zero;
//底部窗口句柄
Window _backgroundWindow = null;
//顶部窗口
Window _foregroundWindow = null;
//顶部窗口的Content
FrameworkElement? _foreroundContent;
//嵌入窗口的区域
RectangleGeometry? _clipRect;
private void NativeHost_LayoutUpdated(object? sender, EventArgs e)
{if (_foreroundContent == null) _foreroundContent = _foregroundWindow.Content as FrameworkElement;//计算控件在底部窗口的位置var pos = TranslatePoint(new Point(0, 0), _foregroundWindow);var dp = pos - Content.TranslatePoint(new Point(0, 0), _backgroundWindow);Content.Margin = new Thickness(Content.Margin.Left + dp.X, Content.Margin.Top + dp.Y, Content.Margin.Right - dp.X, Content.Margin.Bottom - dp.Y);Content.SetSize(ActualWidth, ActualHeight);//创建clipvar gg = _foreroundContent.Clip as GeometryGroup;if (gg == null){_foreroundContent.Clip = gg = new GeometryGroup();gg.FillRule = FillRule.EvenOdd;var rg = new RectangleGeometry();rg.Rect = new Rect(0, 0, _foreroundContent.ActualWidth, _foreroundContent.ActualHeight);gg.Children.Add(rg);gg.Children.Add(new CombinedGeometry() { Geometry1 = new RectangleGeometry(), Geometry2 = new GeometryGroup() { FillRule = FillRule.Nonzero } });}//底下的rect必须保持和容器大小一致var backRg = gg.Children.First() as RectangleGeometry;//上层形状即为穿透区域,CombinedGeometry类型用于支持任意个区域穿透var foreRg = (gg.Children[1] as CombinedGeometry).Geometry2 as GeometryGroup;if (_clipRect == null){_clipRect = new RectangleGeometry();//添加当前控件的穿透区域foreRg.Children.Add(_clipRect);}var newRect = new Rect(0, 0, _foreroundContent.ActualWidth, _foreroundContent.ActualHeight);//判断窗口大小是否改变if (backRg.Rect != newRect){backRg.Rect = newRect;}pos = TranslatePoint(new Point(0, 0), _foreroundContent);newRect = new Rect(pos.X, pos.Y, ActualWidth, ActualHeight);//判断控件区域是否变化if (_clipRect.Rect != newRect){_clipRect.Rect = newRect;}
}

4、WPF控件放在装饰层

由于clip会截其范围内的所有控件,所有有clip的控件上面放置其他控件是看不到的,但是clip不会截取装饰层的控件,所有我们可将控件放到装饰层。
添加一个装饰器属性,在xaml中使用

public class HwndHostBottomEmbbeder : FrameworkElement{public UIElement Adorner{get { return (UIElement)GetValue(ContentProperty); }set { SetValue(ContentProperty, value); }}
}  

定义一个装饰器对象

class NormalAdorner : Adorner
{UIElement _child;/// <summary>/// 构造方法/// </summary>/// <param name="adornedElement">被添加装饰器的元素</param>/// <param name="child">放到装饰器中的元素</param>public NormalAdorner(UIElement adornedElement, UIElement child) : base(adornedElement){_child = child;AddVisualChild(child);}public UIElement Child => _child;protected override Visual GetVisualChild(int index) => _child;protected override int VisualChildrenCount => 1;protected override System.Windows.Size ArrangeOverride(Size finalSize){_child.Arrange(new Rect(new Point(0, 0), finalSize));return finalSize;}
}

在初始化代码中将xaml中设置的Adorner属性的控件加入到装饰层。要注意添加一个容器用于获取鼠标事件,将事件透传到原本的控件(clip后无法响应鼠标事件)。

var layer = AdornerLayer.GetAdornerLayer(c);
if (layer == null)throw new Exception("获取控件装饰层失败,控件可能没有装饰层!");                       
var grid = new Grid();
grid.Background = Brushes.Transparent;
grid.DataContext = c;
grid.SetBinding(Grid.VisibilityProperty, new Binding("Visibility") { Mode = BindingMode.OneWay });
//事件透传
c.MouseByPassFrom(grid);
if (adronerContent != null)
{grid.Children.Add(adronerContent);
}
layer.Add(new NormalAdorner((UIElement)c, grid));

二、完整代码

1、对象定义

 /************************************************************************* @Project:  	HwndHostBottomEmbbeder* @Decription:  底部Hwnd嵌入器,是一个控件,可包含HwndHost控件将其变成底部嵌入,wpf控件显示在装饰层上。*               当前版本使用限制:*               1、窗口需要设置WindowChrome,*               2、会占用Window.Content的Clip属性,*               3、不能点击穿透到Hwnd窗口。*               4、不支持半透明或全透明背景色窗口,因为嵌入hwnd窗口拖动会有残影。*               当前版本适用于显示视频之类的不需要交互的hwnd控件。* @Verision:  	v1.0.0* @Author:  	Xin Nie* @Create:  	2024/03/29 17:33:00* @LastUpdate:  2024/03/29 17:33:00************************************************************************* Copyright @ 2024. All rights reserved.************************************************************************/
[ContentProperty("Content")]
public class HwndHostBottomEmbbeder : FrameworkElement
{/// <summary>/// HwndHost控件/// </summary>public HwndHost Content { get; set; }/// <summary>/// 装饰层控件/// </summary>public UIElement Adorner { get; set; }
}

2、完整代码

之后上传


三、使用示例

1、嵌入Winform控件

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"xmlns:ac="clr-namespace:AC"mc:Ignorable="d"Background="Transparent"WindowStyle="None"   ResizeMode="NoResize"Title="MainWindow" Height="360" Width="640"       xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"  ><WindowChrome.WindowChrome><WindowChrome GlassFrameThickness="-1"   CaptionHeight="0"   /></WindowChrome.WindowChrome ><Grid  Margin="0" Background="#ffffffff"  ><local:HwndHostBottomEmbbeder   Height="200" Width="200" ><!--将WindowsFormsHost转换到底部--><WindowsFormsHost><wf:TextBox  Text="WinForm Text Box"    BackColor="255,	77,78,141" /></WindowsFormsHost><!--在装饰层放wpf控件--><local:HwndHostBottomEmbbeder.Adorner><ToggleButton Margin="5"  Width="25" Height="30" Cursor="Hand"  ><ToggleButton.Template><ControlTemplate TargetType="ToggleButton"><Grid Background="Transparent"><Polygon x:Name="pol" Points="0,0 25,15 0,30" Fill="Gray" Visibility="Visible"></Polygon><Rectangle  x:Name="rec1" HorizontalAlignment="Left" Width="8" Fill="Gray" Visibility="Hidden"></Rectangle><Rectangle  x:Name="rec2" HorizontalAlignment="Right"   Width="8" Fill="Gray" Visibility="Hidden"></Rectangle></Grid></ControlTemplate></ToggleButton.Template></ToggleButton></local:HwndHostBottomEmbbeder.Adorner></local:HwndHostBottomEmbbeder></Grid>
</Window>

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

2、显示视频

示例代码依赖了《播放器》
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"xmlns:ac="clr-namespace:AC"mc:Ignorable="d"Background="Transparent"WindowStyle="None"   ResizeMode="NoResize"Title="MainWindow" Height="360" Width="640"    xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"  ><WindowChrome.WindowChrome><WindowChrome GlassFrameThickness="-1"   CaptionHeight="0"   /></WindowChrome.WindowChrome ><Grid  Margin="0" Background="#ffffffff"  ><local:HwndHostBottomEmbbeder   Height="200" Width="200" ><!--将WindowsFormsHost转换到底部--><WindowsFormsHost><wf:TextBox  x:Name="tb_video" Text="WinForm Text Box"    BackColor="255,77,78,141" /></WindowsFormsHost><!--在装饰层放wpf控件--><local:HwndHostBottomEmbbeder.Adorner><Border Width="150" Height="150" ><ToggleButton Margin="5"  Width="25" Height="30" Cursor="Hand"   Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked"><ToggleButton.Template><ControlTemplate TargetType="ToggleButton"><Grid Background="Transparent"><Polygon x:Name="pol" Points="0,0 25,15 0,30" Fill="Gray" Visibility="Visible"></Polygon><Rectangle  x:Name="rec1" HorizontalAlignment="Left" Width="8" Fill="Gray" Visibility="Hidden"></Rectangle><Rectangle  x:Name="rec2" HorizontalAlignment="Right"   Width="8" Fill="Gray" Visibility="Hidden"></Rectangle></Grid><ControlTemplate.Triggers><Trigger Property="IsChecked" Value="True"><Setter TargetName="pol" Property="Visibility" Value="Hidden"></Setter><Setter TargetName="rec1" Property="Visibility" Value="Visible"></Setter><Setter TargetName="rec2" Property="Visibility" Value="Visible"></Setter></Trigger></ControlTemplate.Triggers></ControlTemplate></ToggleButton.Template></ToggleButton></Border></local:HwndHostBottomEmbbeder.Adorner></local:HwndHostBottomEmbbeder></Grid>
</Window>

MainWindow.xaml.cs

using AC;
using System.Windows;namespace WpfHwndElement
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{Play _play;public MainWindow(){InitializeComponent();}private void ToggleButton_Checked(object sender, RoutedEventArgs e){if (_play == null){_play = new Play();_play.IsLoop = true;//获取tb_video的句柄,通过句柄渲染_play.Window = tb_video.Handle;_play.HardwareAccelerateType = HardwareAccelerateType.Dxva2;//开始播放,播放器会在传入的句柄窗口中渲染视频。_play.Start(@"D:\测试\Sony_4K_Camp_Main.mp4");      }else{_play.IsPause = false;}}private void ToggleButton_Unchecked(object sender, RoutedEventArgs e){_play.IsPause = true;}}
}

效果预览
效

3、圆角矩形视频

示例代码依赖了《播放器》
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"xmlns:ac="clr-namespace:AC"mc:Ignorable="d"Background="Transparent"WindowStyle="None"   ResizeMode="NoResize"Title="MainWindow" Height="360" Width="640"   ac:Resize.IsResizeable="True"ac:Resize.IsWindowDragSmooth="True"ac:Move.IsDragMoveable="True"      xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"  ><WindowChrome.WindowChrome><WindowChrome GlassFrameThickness="-1"   CaptionHeight="0"   /></WindowChrome.WindowChrome ><Grid  Margin="0" Background="#ffffffff"  ><local:HwndHostBottomEmbbeder   Height="200" Width="200"   ><!--裁剪圆角矩形--><local:HwndHostBottomEmbbeder.Clip><RectangleGeometry Rect="0 0 200 200" RadiusX="10" RadiusY="10"></RectangleGeometry></local:HwndHostBottomEmbbeder.Clip><!--将WindowsFormsHost转换到底部--><WindowsFormsHost><wf:TextBox  x:Name="tb_video" Text="WinForm Text Box"  BorderStyle="None"  BackColor="255,77,78,141" /></WindowsFormsHost><!--在装饰层放wpf控件--><local:HwndHostBottomEmbbeder.Adorner><Border Width="150" Height="150" ><ToggleButton Margin="5"  Width="25" Height="30" Cursor="Hand"   Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked"><ToggleButton.Template><ControlTemplate TargetType="ToggleButton"><Grid Background="Transparent"><Polygon x:Name="pol" Points="0,0 25,15 0,30" Fill="Gray" Visibility="Visible"></Polygon><Rectangle  x:Name="rec1" HorizontalAlignment="Left" Width="8" Fill="Gray" Visibility="Hidden"></Rectangle><Rectangle  x:Name="rec2" HorizontalAlignment="Right"   Width="8" Fill="Gray" Visibility="Hidden"></Rectangle></Grid><ControlTemplate.Triggers><Trigger Property="IsChecked" Value="True"><Setter TargetName="pol" Property="Visibility" Value="Hidden"></Setter><Setter TargetName="rec1" Property="Visibility" Value="Visible"></Setter><Setter TargetName="rec2" Property="Visibility" Value="Visible"></Setter></Trigger></ControlTemplate.Triggers></ControlTemplate></ToggleButton.Template></ToggleButton></Border></local:HwndHostBottomEmbbeder.Adorner></local:HwndHostBottomEmbbeder></Grid>
</Window>

MainWindow.xaml.cs
cs代码同上略。
效果预览
在这里插入图片描述

4、拖动位置大小

示例代码依赖了《拖动》和《调整大小》还有《播放器》
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"xmlns:ac="clr-namespace:AC"mc:Ignorable="d"Background="Transparent"WindowStyle="None"   ResizeMode="NoResize"Title="MainWindow" Height="360" Width="640"   ac:Resize.IsResizeable="True"ac:Move.IsDragMoveable="True"      xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"  ><WindowChrome.WindowChrome><WindowChrome GlassFrameThickness="-1"   CaptionHeight="0"   /></WindowChrome.WindowChrome ><Grid  Margin="0" Background="#ffffffff"  ><local:HwndHostBottomEmbbeder   Height="200" Width="200"  ac:Resize.IsResizeable="True"  ac:Move.IsDragMoveable="True" ><!--将WindowsFormsHost转换到底部--><WindowsFormsHost><!--使用窗体设置全透明--><wf:Form  x:Name="tb_video"  TopLevel="False" FormBorderStyle="None"  /></WindowsFormsHost><!--在装饰层放wpf控件--><local:HwndHostBottomEmbbeder.Adorner><!--非播放时wpf层填充颜色,避免直接透到桌面--><Border x:Name="bd_mask"  Background="RoyalBlue"><ToggleButton Margin="5"  Width="25" Height="30" Cursor="Hand"   Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked"><ToggleButton.Template><ControlTemplate TargetType="ToggleButton"><Grid Background="Transparent"><Polygon x:Name="pol" Points="0,0 25,15 0,30" Fill="Gray" Visibility="Visible"></Polygon><Rectangle  x:Name="rec1" HorizontalAlignment="Left" Width="8" Fill="Gray" Visibility="Hidden"></Rectangle><Rectangle  x:Name="rec2" HorizontalAlignment="Right"   Width="8" Fill="Gray" Visibility="Hidden"></Rectangle></Grid><ControlTemplate.Triggers><Trigger Property="IsChecked" Value="True"><Setter TargetName="pol" Property="Visibility" Value="Hidden"></Setter><Setter TargetName="rec1" Property="Visibility" Value="Visible"></Setter><Setter TargetName="rec2" Property="Visibility" Value="Visible"></Setter></Trigger></ControlTemplate.Triggers></ControlTemplate></ToggleButton.Template></ToggleButton></Border></local:HwndHostBottomEmbbeder.Adorner></local:HwndHostBottomEmbbeder></Grid>
</Window>

MainWindow.xaml.cs

using AC;
using System.Reflection;
using System.Windows;namespace WpfHwndElement
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{Play _play;public MainWindow(){InitializeComponent();                 }private void ToggleButton_Checked(object sender, RoutedEventArgs e){if (_play == null){_play = new Play();_play.IsLoop = true;//获取tb_video的句柄,通过句柄渲染_play.Window = tb_video.Handle;_play.HardwareAccelerateType = HardwareAccelerateType.Dxva2;//开始播放,播放器会在传入的句柄窗口中渲染视频。_play.Start(@"D:\Sony_4K_Camp.mp4");//实现透明窗口,避免拖动时与视频绘制冲突,出现界面闪烁tb_video.GetType().GetMethod("SetStyle", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(tb_video, new object[] { ControlStyles.Opaque, true });}else{_play.IsPause = false;}bd_mask.Background =System.Windows.Media. Brushes.Transparent;}private void ToggleButton_Unchecked(object sender, RoutedEventArgs e){_play.IsPause = true;bd_mask.Background = System.Windows.Media.Brushes.RoyalBlue;}}
}

在这里插入图片描述


总结

以上就是今天要讲的内容,本章的实现是有一定难度的,其灵感来源有flutter,也是刚好发现wpf的Clip属性能做到穿透,才有了实现本章的基础,但是限制也不小,当然作为初步探索的版本,以后可以继续优化。本章实现的嵌入方式虽然有限制,但还是能够用来做视频渲染的,尤其是需要做圆角边框以及拖动的场景,就能做到渲染性能和界面效果的完美结合。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何理解模板?

文章目录 1. 泛型编程2.函数模板2.1函数模板概念2.1函数模板格式2.3函数模板的原理2.4函数模板的实例化2.5模板参数的匹配原则 3.类模板3.1类模板的定义格式3.2类模板的实例化 1. 泛型编程 如何实现一个通用的交换函数呢&#xff1f; void Swap(int& left, int& right)…

4t 15届第3套模拟

一、Seg &#xff01;&#xff01;&#xff01;难点 1.上下限&#xff1a; 这种上下限的有种情况是 ①通过按键直接实现&#xff1a;那就是按一下一下 ②通过按键操作标志位在数码管实现&#xff1a;我没要对他进行操作&#xff0c;但是默认就是0&#xff0c;那你不能0就吧&a…

配置 施耐德 modbusTCP 分布式IO子站 RPA0100

1. 总体步骤 2. 软件组态&#xff1a;在 Unity Pro 软件中创建编辑 PRA 模块工程 2.1 新建项目 模块箱硬件型号如下 点击 Unity Pro 软件左上方【新建】按钮&#xff0c;选择正确的 DIO 模块型号、背板型号 2.2 模块组态 2.2.1 拖拽添加模块 双击【配置】菜单下的【0&…

安全防御产品—锐安盾重磅上线,助力更安全、更流畅的业务体验

在互联网时代&#xff0c;互联网技术蓬勃发展&#xff0c;然而&#xff0c;随之而来的网络安全问题也备受关注。诸如DDoS攻击、CC攻击、常见Web攻击等攻击手段突如其来&#xff0c;导致企业业务中断&#xff0c;严重影响企业业务正常运行。对此&#xff0c;锐成云重磅推出安全防…

数据删除如何恢复?使用 3 个适用于 Windows 的最佳数据恢复工具方法

您是否在将重要文件从一个位置移动到另一个位置时丢失了这些文件&#xff0c;或者在此过程中意外删除了它们&#xff1f;您是否在恶意软件损坏外部存储设备后格式化外部存储设备时丢失了数据&#xff1f;即使您没有备份也不必担心。 3 个适用于 Windows 的最佳数据恢复工具方法…

【计算机网络】select/poll

多路转接 - select/poll 一、I/O 多路转接之 select1. select 接口2. select 的使用3. select 的优缺点 二、I/O 多路转接之 poll1. poll 接口2. poll 的使用3. poll 与 select 的对比 一、I/O 多路转接之 select 多路转接属于 IO 复用方式的一种。系统提供 select() 函数来实…

# 达梦数据库知识点

达梦数据库知识点 测试数据 -- SYSDBA.TABLE_CLASS_TEST definitionCREATE TABLE SYSDBA.TABLE_CLASS_TEST (ID VARCHAR(100) NOT NULL,NAME VARCHAR(100) NULL,CODE VARCHAR(100) NULL,TITLE VARCHAR(100) NULL,CREATETIME TIMESTAMP NULL,COLUMN1 VARCHAR(100) NULL,COLUMN…

入门教程:Windows搭建C语言和EasyX开发环境

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; 如果对你…

C++ list

文章目录 list的介绍及使用list的介绍list的构造list iterator的使用list capacitylist element accesslist modifiers list模拟实现list节点类list迭代器类list类 list深度剖析list迭代器失效list反向迭代器 list与vector对比 list的介绍及使用 list的介绍 1.list的底层是双向…

Linux中JMeter的使用

Linux中JMeter的使用 Linux版本JMeter安装 # 1、下载、安装JMeter 如果有安装包直接上传即可 wget -c https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-5.4.1.tgz # 解压 tar -zxvf apache-jmeter-5.4.1.tgz -C /usr/local/sjdwz_test cd /usr/local/sjdwz_t…

idea2023+jdk1.8+Maven3.6.3+Testng6.10+junit4.13搭建测试

idea2023jdk1.8Maven3.6.3Testng6.10junit4.13搭建测试 首先创建maven工程 导入依赖 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/…

electron 打不同环境的包

我用的打包工具: electron-builder 1、在package.json 文件的同级下创建2个js文件 electron-builder-test.config.js electron-builder.config.js electron-builder-test.config.js const basejson require(./electron-builder.config.js); module.exports {extraMetada…