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

记录.Net中使用WMI的一些坑,触摸失效和发布增加 PublishTrimmed裁剪异常

1. 在没有报异常的情况下触控屏获取触摸失效。

在做触摸屏笔书写的时候,我们WPF可以获取到笔的压感值,今天测试的时候突然发现压感失效了,笔迹的书写压感效果没有了。然后一致怀疑书写组件配置的问题或是实现的问题。测试了好久 。

最后通过控制变量一步步注释代码,使用最简单Demo测试。最后发现在调用Wmi方法会触发InvalidCastException导致获取压感触摸失效。最后改为通过Cim获取Sn就没有问题了。此问题只有在.Net Core和.net版本有,在 .NET Framework 框架是没问题的。

System.InvalidCastException: 没有注册接口at MS.Win32.Penimc.UnsafeNativeMethods.CoCreateInstance(Guid& clsid, Object punkOuter, Int32 context, Guid& iid)at MS.Win32.Penimc.UnsafeNativeMethods.CreatePimcManager()

下面是测试Demo

using System.Diagnostics;
using System.Management;
using System.Text;
using System.Windows;
using System.Windows.Annotations;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using H3C.Board.Core;
using Microsoft.Management.Infrastructure;namespace WpfApp1
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{public MainWindow(){AppDomain.CurrentDomain.FirstChanceException += (sender, args) =>{Debug.WriteLine(args.Exception);};InitializeComponent();//WmiGetSerialNumberInfo();//立即Window初始化的时候调用Wmi会抛出FirstChanceException,Grid_StylusDown就不会触发了Loaded += MainWindow_Loaded;}private void MainWindow_Loaded(object sender, RoutedEventArgs e){WmiGetSerialNumberInfo(); //Loaded之后调用不会有问题,}private void Grid_StylusDown(object sender, StylusDownEventArgs e){var pressure = GetPressureValue(e);var point = e.GetPosition(this);Console.WriteLine($"开始记录压感 - 位置: {point}, 压感: {pressure:F4}");}private void Grid_StylusMove(object sender, StylusEventArgs e){var pressure = GetPressureValue(e);var point = e.GetPosition(this);// 实时显示压感值DisplayPressureInfo(point, pressure);}private void Grid_StylusUp(object sender, StylusEventArgs e){var pressure = GetPressureValue(e);var point = e.GetPosition(this);}private double GetPressureValue(StylusEventArgs e){try{var stylusPoints = e.GetStylusPoints(this);if (stylusPoints.Count > 0){return stylusPoints[0].PressureFactor;}}catch (Exception ex){Console.WriteLine($"获取压感值失败: {ex.Message}");}return 0.0;}private void DisplayPressureInfo(Point point, double pressure){// 在UI上显示压感信息Console.WriteLine($"实时压感 - X: {point.X:F1}, Y: {point.Y:F1}, Pressure: {pressure:F4}");// 可以更新UI控件显示压感值// 更新文本显示PressureDisplay.Text = $"压感: {pressure:F4}";// 更新可视化指示器PressureIndicator.Visibility = Visibility.Visible;Canvas.SetLeft(PressureIndicator, point.X - 10);Canvas.SetTop(PressureIndicator, point.Y - 10);// 根据压感调整指示器大小和颜色var size = 10 + (pressure * 30); // 压感越大,圆圈越大PressureIndicator.Width = size;PressureIndicator.Height = size;// 根据压感调整颜色var colorIntensity = (byte)(pressure * 255);PressureIndicator.Fill = new SolidColorBrush(Color.FromRgb(255, (byte)(255 - colorIntensity), (byte)(255 - colorIntensity)));}/// <summary>/// 使用Cim不会触摸失效/// </summary>/// <returns></returns>public static string? GetComputerSn(){try{// 创建本地 CIM 会话using var session = CimSession.Create(null);// 查询 Win32_BIOS 类var instances = session.QueryInstances(@"root\cimv2", "WQL", "SELECT SerialNumber FROM Win32_BIOS");foreach (var instance in instances){var snProperty = instance.CimInstanceProperties["SerialNumber"];if (snProperty?.Value == null) continue;string? sn = snProperty.Value.ToString()?.Trim();if (string.IsNullOrEmpty(sn)) continue;// 检查是否为无效的默认值(常见于一些 OEM 厂商)if (sn.Contains("O.E.M", StringComparison.OrdinalIgnoreCase) ||sn.Contains("OEM", StringComparison.OrdinalIgnoreCase) ||sn.Equals("Default", StringComparison.OrdinalIgnoreCase) ||sn.Equals("Default string", StringComparison.OrdinalIgnoreCase) ||sn.Equals("To be filled by O.E.M.", StringComparison.OrdinalIgnoreCase)){continue; // 跳过无效的序列号}return sn;}}catch{//}return string.Empty;}private void WmiGetSerialNumberInfo(){try{// 创建 WMI 查询ManagementObjectSearcher searcher = new("SELECT SerialNumber FROM Win32_BIOS");// 遍历查询结果foreach (ManagementObject obj in searcher.Get()){string serialNumber = obj["SerialNumber"]?.ToString();if (!string.IsNullOrEmpty(serialNumber)){Console.WriteLine($"BIOS 序列号: {serialNumber}");return;}}Console.WriteLine("未找到 BIOS 序列号信息");}catch (ManagementException ex){Console.WriteLine($"WMI 查询错误: {ex.Message}");}catch (Exception ex){Console.WriteLine($"WMI 查询异常错误: {ex.Message}");}}private void ButtonBase_OnClick(object sender, RoutedEventArgs e){WmiGetSerialNumberInfo();}}}
<Windowx:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:core="clr-namespace:H3C.Board.Core;assembly=H3C.Board.Core"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:local="clr-namespace:WpfApp1"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Title="MainWindow"Width="1000"Height="800"Background="Transparent"ShowInTaskbar="False"Stylus.IsPressAndHoldEnabled="False"Stylus.IsTapFeedbackEnabled="False"WindowChrome.ResizeGripDirection="None"WindowStartupLocation="CenterScreen"WindowStyle="None"mc:Ignorable="d"><GridBackground="LightGray"StylusDown="Grid_StylusDown"StylusMove="Grid_StylusMove"StylusUp="Grid_StylusUp"><!--  压感值显示  --><TextBlockx:Name="PressureDisplay"Margin="30"HorizontalAlignment="Left"VerticalAlignment="Top"FontSize="16"FontWeight="Bold"Foreground="Blue" /><!--  压感可视化指示器  --><Ellipsex:Name="PressureIndicator"Width="20"Height="20"HorizontalAlignment="Left"VerticalAlignment="Top"Fill="Red"Visibility="Collapsed" /><ButtonWidth="30"Height="30"Click="ButtonBase_OnClick" /></Grid>
</Window>

.net8使用WMI可能还有一些意想不到的坑,建议都替换成CIMI。

此问题lindexi已经报告给 WPF 官方,请看 https://github.com/dotnet/wpf/issues/9752

2. 在.Net8发布增加 PublishTrimmed 裁剪选项,调用WMI 的ManagementObject 异常

下面是转自wutangyuan的博客:https://www.cnblogs.com/wuty/p/18931865

最近在做OTA的功能,需要获取到sn做一些业务的逻辑。我们自己实现的库里边的,大部分都是调用 System.Management 的 ManagementObjectSearcher 获取 Bios 的序列号

如下所示:

 private void BtnWmi_OnClick(object sender, RoutedEventArgs e){try{// 创建 WMI 查询ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT SerialNumber FROM Win32_BIOS");
// 遍历查询结果foreach (ManagementObject obj in searcher.Get()){string serialNumber = obj["SerialNumber"]?.ToString();
if (!string.IsNullOrEmpty(serialNumber)){Console.WriteLine($"BIOS 序列号: {serialNumber}");return;}}Console.WriteLine("未找到 BIOS 序列号信息");}catch (ManagementException ex){Console.WriteLine($"WMI 查询错误: {ex.Message}");}catch (Exception ex){Console.WriteLine($"WMI 查询异常错误: {ex.Message}");}}

由于我们项目现在新建的项目都是基于.Net 8 开发,而且为了兼容多种设备和系统,我们目前的打包方式都是以发布独立部署的方式

同时为了能减少输出文件的大小,我们会启用裁剪的方式 <PublishTrimmed>true</PublishTrimmed>

  <PublishTrimmed>true</PublishTrimmed><_SuppressWpfTrimError>true</_SuppressWpfTrimError><BuiltInComInteropSupport>true</BuiltInComInteropSupport><TrimMode>partial</TrimMode>

以上准备工作做好,发布以上的程序,运行发现如下的错误:

查询了官网的资料,有如下的说明:剪裁选项 - .NET | Microsoft Learn

就是启用裁剪会禁用掉某些框架的功能。

解决方法:

参考:使用 C# 远程连接到 WMI - Win32 apps | Microsoft Learn

使用 Microsoft.Management.Infrastructure 的 CimSession 替换WMI 早期的版本

如下所示:

 using Microsoft.Management.Infrastructure;private void BtnCim_OnClick(object sender, RoutedEventArgs e){try{// 创建本地CIM会话using (var session = CimSession.Create(null)){// 查询Win32_BIOS类var instances = session.QueryInstances(@"root\cimv2", "WQL", "SELECT SerialNumber FROM Win32_BIOS");foreach (var instance in instances){var serialNumber = instance.CimInstanceProperties["SerialNumber"].Value?.ToString();Console.WriteLine($"BIOS 序列号: {serialNumber}");}}}catch (Exception ex){Console.WriteLine($"错误: {ex.Message}");}}

不修改发布选项的情况下,运行如下:是可以获取得到Bios的sn的

总结:

1、推荐使用 Microsoft.Management.Infrastructure 的 CimSession 替换 WMI 旧版的 ManagementObject

2、裁剪的选项 PublishTrimmed 如果不介意应用程序的一点体积,是可以忽略不加

代码Demo 链接:wutangyuan/wutyDemo: Demo代码备份

http://www.wxhsa.cn/company.asp?id=509

相关文章:

  • 多态--成员变量、成员函数、静态函数
  • Linux操作系统相关问题汇总
  • Java学习
  • 鲜花 9.10
  • 【工具】配置笔记本电脑安装centos7关闭盖子不休眠
  • 括号匹配
  • ECT-OS-JiuHuaShan框架的真正意义是打破还原论和人类中心论,公理是客观存在与数学逻辑,不依赖于人类理解与否。
  • z-index的使用方案
  • 再见 PS!豆包 Seedream 4.0 发布,图片生成、合成、编辑、美颜…,一句话搞定!!
  • 鲜花 9.10 - Gon
  • Iframe 全屏嵌入实验
  • 全面获取TSC频率:提升性能分析与基准测试精度
  • 【rdma】RoCE、IB和TCP等网络的基本知识及差异对比
  • WindTerm_2.7.0
  • VMWare Esxi防火墙添加白名单访问及ip异常无法登录解决办法
  • 鸿蒙,下一个iPhone时刻?
  • dw
  • 5%付费率背后,鸿蒙成独立开发者的“商业理想国”
  • HarmonyOS编写教师节贺卡
  • 3天赚2万!开发者的梦想也可以掷地有声!
  • 【IoTDB 线上小课 19】开源时序数据库 Apache IoTDB,四大优势解决企业选型难题!
  • java课前问题思考
  • nano快捷键指南
  • 个人开发者从0到1(BeeCount:一款开源的跨平台个人记账应用)
  • 网络通信中的死锁
  • 学生开发者经验|豆包大模型 + TRAE,让 AI 应用快速落地
  • java课前问题
  • CSP-S模拟19
  • union类型
  • PDE,广义特征问题,和神经特征函数法