演练 dotnet 使用 GeneratedComInterface 源代码生成方式调用 COM 接口

news/2025/1/22 7:18:50/文章来源:https://www.cnblogs.com/lindexi/p/18684914

官方文档:

  • ComWrappers source generation - .NET Microsoft Learn
  • Using the ComWrappers API - .NET Microsoft Learn

本文将演练在 WPF 应用里面手动写 COM 调用的方式,调用打开文件对话框。访问 COM 的方式为源代码生成器方式

本文内容里面只给出关键代码片段,如需要全部的项目文件,可到本文末尾找到本文所有代码的下载方法

必要的基础库安装:

    <PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.106"><PrivateAssets>all</PrivateAssets><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets></PackageReference>

编写 NativeMethods.txt 添加 Win32 方法调用

CoInitializeEx
CoCreateInstance
CoGetClassObject

上述逻辑详细请看 dotnet 使用 CsWin32 库简化 Win32 函数调用逻辑

编写 IFileOpenDialog 接口,代码如下

using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;namespace NearnearfayyerchodaiHikelahuhaw;[GeneratedComInterface(Options = ComInterfaceOptions.ComObjectWrapper)]
[Guid("d57c7288-d4ad-4768-be02-9d969532d960")]
internal partial interface IFileOpenDialog
{void Show(IntPtr owner);
}

在 MainWindow 的 Loaded 事件调用,代码如下

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.Marshalling;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
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 Windows.Win32.System.Com;
using System.Runtime.Versioning;
using System.Windows.Interop;namespace NearnearfayyerchodaiHikelahuhaw;public partial class MainWindow : Window
{public MainWindow(){InitializeComponent();Loaded += MainWindow_Loaded;}private unsafe void MainWindow_Loaded(object sender, RoutedEventArgs e){//Windows.Win32.PInvoke.CoInitializeEx(null, COINIT.COINIT_APARTMENTTHREADED | COINIT.COINIT_DISABLE_OLE1DDE);var cw = new StrategyBasedComWrappers();var rclsid = Guid.Parse("DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7");var riid = Guid.Parse("d57c7288-d4ad-4768-be02-9d969532d960");void* ppv;var hr = CoCreateInstance(&rclsid, IntPtr.Zero,CLSCTX.CLSCTX_ALL, &riid, &ppv);hr.ThrowOnFailure();var fileOpenDialog = (IFileOpenDialog) cw.GetOrCreateObjectForComInstance(new IntPtr(ppv), CreateObjectFlags.None);var windowInteropHelper = new WindowInteropHelper(this);fileOpenDialog.Show(windowInteropHelper.Handle);}[DllImport("OLE32.dll", ExactSpelling = true)][DefaultDllImportSearchPaths(DllImportSearchPath.System32)][SupportedOSPlatform("windows5.0")]internal static extern unsafe Windows.Win32.Foundation.HRESULT CoCreateInstance(global::System.Guid* rclsid, IntPtr pUnkOuter, Windows.Win32.System.Com.CLSCTX dwClsContext, global::System.Guid* riid, void* ppv);
}

运行代码,即可看到弹出打开文件对话框

由于当前正在 WPF 线程里执行 Loaded 事件的逻辑,因此 CoInitializeEx 是可不调用的。在 WPF 框架内部已经帮忙调用了

以上代码重新定义 CoCreateInstance 是为了获取 ppv 指针

以上的 IFileOpenDialog 将生成以下代码

// <auto-generated />
#pragma warning disable CS0612, CS0618
file unsafe class InterfaceInformation : global::System.Runtime.InteropServices.Marshalling.IIUnknownInterfaceType
{public static global::System.Guid Iid { get; } = new([136, 114, 124, 213, 173, 212, 104, 71, 190, 2, 157, 150, 149, 50, 217, 96]);public static void** ManagedVirtualMethodTable => null;
}[global::System.Runtime.InteropServices.DynamicInterfaceCastableImplementationAttribute]
file unsafe partial interface InterfaceImplementation : global::NearnearfayyerchodaiHikelahuhaw.IFileOpenDialog
{[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Interop.ComInterfaceGenerator", "9.0.11.11010")][global::System.Runtime.CompilerServices.SkipLocalsInitAttribute]void global::NearnearfayyerchodaiHikelahuhaw.IFileOpenDialog.Show(nint owner){var(__this, __vtable_native) = ((global::System.Runtime.InteropServices.Marshalling.IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey(typeof(global::NearnearfayyerchodaiHikelahuhaw.IFileOpenDialog));int __invokeRetVal;{__invokeRetVal = ((delegate* unmanaged[MemberFunction]<void*, nint, int> )__vtable_native[3])(__this, owner);}// NotifyForSuccessfulInvoke - Keep alive any managed objects that need to stay alive across the call.global::System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(__invokeRetVal);global::System.GC.KeepAlive(this);}
}file unsafe partial interface InterfaceImplementation
{
}file unsafe partial interface InterfaceImplementation
{
}namespace NearnearfayyerchodaiHikelahuhaw
{[global::System.Runtime.InteropServices.Marshalling.IUnknownDerivedAttribute<InterfaceInformation, InterfaceImplementation>]internal partial interface IFileOpenDialog{}
}namespace NearnearfayyerchodaiHikelahuhaw
{internal partial interface IFileOpenDialog{}
}

本文代码放在 github 和 gitee 上,可以使用如下命令行拉取代码。我整个代码仓库比较庞大,使用以下命令行可以进行部分拉取,拉取速度比较快

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 333ee4d7f57cdecc80be1835a210a5d39a00d8a6

以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 333ee4d7f57cdecc80be1835a210a5d39a00d8a6

获取代码之后,进入 WPFDemo/NearnearfayyerchodaiHikelahuhaw 文件夹,即可获取到源代码

更多技术博客,请参阅 博客导航

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

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

相关文章

演练 dotnet 使用 函数指针 调用 COM 接口

本文将和大家演练如何在 dotnet 里面使用 函数指针 调用 COM 接口,整个过程没有 COM 封装的存在,其性能非常高,调用非常直接和底层,无中间商赚差价官方文档: 函数指针 - C# feature specifications Microsoft Learn ComWrappers source generation - .NET Microsoft Learn…

读量子霸权11基因剪辑

读量子霸权11基因剪辑1. 癌症 1.1. 癌症是美国人口死亡病因中排名第二的“杀手”​,仅次于心血管疾病1.1.1. 虽然手术、化学治疗和放射治疗等医学手段在对抗癌症方面取得了越来越多的进展,但因癌症而死亡的人数仍然居高不下1.2. 人类与癌症之间的战争尚存在一个根本问题没有得…

Wi-Fi 8:开创连接的未来

Wi-Fi 8:开创连接的未来 下一代 Wi-Fi 8。主要见解包括:多 AP 协调 进一步优化频谱效率 扩展范围 能效改进然而,Wi-Fi 8 优先考虑无线通信的一个方面,这个方面变得越来越重要:可靠性。 Wi-Fi 8 的 8021.1 亿则专注于“超高可靠性”。 本白皮书讨论了 Wi-Fi 8 的新功能、蜂…

请说说什么是分区响应图?

分区响应图在前端开发中是一种特殊的技术实现,它允许开发者将一张图片划分为多个区域,并为每个区域指定不同的超链接或响应行为。当用户点击图片的不同区域时,会根据该区域的设置触发相应的操作,比如跳转到不同的网页或执行特定的JavaScript函数。 以下是关于分区响应图的详…

用于非均匀二次谐波产生的光子集成电路

用于非均匀二次谐波产生的光子集成电路 摘要:GaAs基激光器与倍频波导的异质集成为在所谓的绿隙中实现可扩展相干源提供了一条清晰的途径,但到目前为止,倍频系统一直依赖于单独制造的激光器来提供足够的功率用于二次谐波产生。在这项工作中,提出了一种光子集成电路(PIC),…

迈向基于离子的大规模集成电路:离子电子元件的电路级设计、仿真和集成

迈向基于离子的大规模集成电路:离子电子元件的电路级设计、仿真和集成 离子电子学将离子作为电荷载体与类电子操作相结合,实现了独特的信息处理、化学调节和增强的生物可整合性。标准仿真工具在有效模拟集成离子电子元件的行为方面遇到了困难,这突显了对专门设计和仿真方法的…

推荐书籍《AI芯片开发核心技术详解》、《智能汽车传感器:原理设计应用》、《TVM编译器原理与实践》、《LLVM编译器原理与实践》,谢谢

4本书推荐《AI芯片开发核心技术详解》、《智能汽车传感器:原理设计应用》、《TVM编译器原理与实践》、《LLVM编译器原理与实践》由清华大学出版社资深编辑赵佳霓老师策划编辑的新书《AI芯片开发核心技术详解》已经出版,京东、淘宝天猫、当当等网上,相应陆陆续续可以购买。该…

JavaScript的其他常用库

setTimeout与setInterval、requestAnimationFrame、Map与Set、localStorage、JSON、日期、WebSocket、window、canvas等常用库ε=ε=ε=(~ ̄▽ ̄)~setTimeout与setIntervalsetTimeout(func, delay) :delay毫秒后,执行函数func()。 例如: let main = function() {let $div =…

内外网安全文件交换系统:守护企业数据安全的坚固防线

介绍内外网安全文件交换系统的使用在当今数字化时代,企业内外网数据交换的需求日益增长,但数据安全问题也愈发突出。如何在保障数据高效传输的同时,确保其安全性?内外网安全文件交换系统给出了完美答案。 一、产品定位与功能亮点 内外网安全文件交换系统是一款专为企业内外…

git 证书验证问题 SSL certificate problem

提示这个 fatal: unable to access https://github.com/example/repo.git/: SSL certificate problem: unable to get local issuer certificate 一般配置证书即可 第一步 导出网站证书第二步 添加导出的证书 具体命令为 git config --global http.sslCAInfo /path/to/root_cer…

Solidity中数据的布局

1.Storage中 1.1-基本原则(基本的值类型) 在这里面的变量都是独立的,互相不影响,所以非常"安全"; 均存储在slot中,slot有2^256个,每个长度256位; 从0开始连续往后存储(除动态数组和映射),当有连续几个都小于256位时,会尝试将它们放在同一个slot中; 同时也…

深入探讨视图更新:提升数据库灵活性的关键技术

title: 深入探讨视图更新:提升数据库灵活性的关键技术 date: 2025/1/21 updated: 2025/1/21 author: cmdragon excerpt: 在现代数据库的管理中,视图作为一种高级的抽象机制,为数据的管理提供了多种便利。它不仅简化了复杂查询的过程,还能用来增强数据的安全性,限制用户对…