如何在C#中使用COM接口

embedded/2025/1/15 6:57:22/

在C++中,可以使用CoCreateInstance函数来创建COM接口的实例。

以下教程可以帮助你方便的在C#中实现同样的功能。

方法一、手动生成(适用于所有.NET版本)

1、确定要使用的COM接口

Windows中很多功能都是通过COM实现的,有时候我们想实现一些系统功能,但是又没有直接的Win32 API代调用,就可以寻找COM接口替代。

至于使用哪个COM接口,这个可以通过搜索引擎。

例如,我想设置桌面壁纸,可以通过IDesktopWallpaper接口来实现。

2、查找COM接口的GUID

这里提供了几种方案

一、通过搜索引擎,常用的COM接口,可以通过搜索引擎直接搜索到GUID

二、对于不常用的COM接口,可能搜索引擎不能搜索到对应的GUID,我们可以创建一个Win32工程(需要Visual Studio安装C++桌面开发),然后输入CLSID_接口名称,再按F12就可以看到GUID。

例如:CLSID_DesktopWallpaper,按F12如下所示

IDesktopWallpaper

三、如果电脑上没有安装C++桌面开发负载,可以访问stevemk14ebr的gist来进行搜索

3、接口声明

有了COM接口的GUID后,我们需要对COM接口进行声明

这里有几个方法可供参考:

一、通过C# + COM接口为关键进行进行搜索

 例如搜索[C# IDesktopWallpaper],然后在结果中查找,一般会有C#的接口声明,如果没找到相关结果,可以查看方法2

二、访问pinvoke.net搜索

我们打开pinvoke.net: the interop wiki!,搜索IDesktopWallpaper

目前该网站已经停止维护,很大机率会搜索不出来。

三、访问MSDN文档,通过数据类型映射,自行声明COM接口

数据类型的映射可以参考下面的文章:

Platform Invoke Data Types | Microsoft Learn

这种方法虽然比较麻烦,但也算是最终解决方案了。

像我平常跟硬件交互比较多,这种映射也是家常便饭了。

需要注意的是,接口中涉及的类型也要进行声明。

例如void SetPosition(DESKTOP_WALLPAPER_POSITION position)参数里涉及了DESKTOP_WALLPAPER_POSITION,我们需要对这个DESKTOP_WALLPAPER_POSITION类型进行定义。

对于POINT或RECT之类的,建议也是自己定义,不要使用C#内置类型,否则有可能会封送失败。

IDesktopWallpaper在C#中声明如下:

 1 [ComVisible(true)]2 public enum DESKTOP_SLIDESHOW_DIRECTION3 {5     DSD_FORWARD = 0,7     DSD_BACKWARD = 18 }9 
10 
11 public struct RECT
12 {
13     public int left;
14     public int top;
15     public int right;
16     public int bottom;
17 }
18 
19 [ComVisible(true)]
20 public enum DESKTOP_WALLPAPER_POSITION
21 {
23     DWPOS_CENTER = 0,
25     DWPOS_TILE = 1,
27     DWPOS_STRETCH = 2,
29     DWPOS_FIT = 3,
31     DWPOS_FILL = 4,
33     DWPOS_SPAN = 5
34 }
37 
38 [ComVisible(true)]
39 [Flags]
40 public enum DESKTOP_SLIDESHOW_STATE
41 {
42     DSS_ENABLED = 1,
44     DSS_SLIDESHOW = 2,
46     DSS_DISABLED_BY_REMOTE_SESSION = 4
47 }
49 
50 [ComImport]
51 [Guid("B92B56A9-8B55-4E14-9A89-0199BBB6F93B")]
52 [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
53 public interface IDesktopWallpaper
54 {
55     void SetWallpaper([MarshalAs(UnmanagedType.LPWStr)] string monitorID, [MarshalAs(UnmanagedType.LPWStr)] string wallpaper);
56     
57     [return: MarshalAs(UnmanagedType.LPWStr)]
58     StringBuilder GetWallpaper([MarshalAs(UnmanagedType.LPWStr)] string monitorID);
59     
60     [return: MarshalAs(UnmanagedType.LPWStr)]
61     StringBuilder GetMonitorDevicePathAt(uint monitorIndex);
62 
63     [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
64     uint GetMonitorDevicePathCount();
65        
66     RECT GetMonitorRECT([MarshalAs(UnmanagedType.LPWStr)] string monitorID);
67   
68     void SetBackgroundColor(uint color);
69  
70     uint GetBackgroundColor();
71 
72     void SetPosition([MarshalAs(UnmanagedType.I4)] DESKTOP_WALLPAPER_POSITION position);
73 
74     [return: MarshalAs(UnmanagedType.I4)]
75     DESKTOP_WALLPAPER_POSITION GetPosition();
76 
77     //未引入IShellItemArray类型,暂时不导入
78     //void SetSlideshow(IShellItemArray items);
79 
80     //未引用IShellItemArray类型,暂时不导入
81     //IShellItemArray GetSlideshow();
82     //IntPtr GetSlideshow();
83 
84     void SetSlideshowOptions(uint options, uint slideshowTick);
85 
86     void GetSlideshowOptions(out uint options, out uint slideshowTick);
87 
88     void AdvanceSlideshow([MarshalAs(UnmanagedType.LPWStr)] string monitorID, [MarshalAs(UnmanagedType.I4)] DESKTOP_SLIDESHOW_DIRECTION direction);
89 
90     DESKTOP_SLIDESHOW_STATE GetStatus();
91 
92     void Enable([MarshalAs(UnmanagedType.Bool)] bool enable);
93 }

4、定义类

这个步骤和步骤3类似,但是不需要定义类的成员函数。这里的GUID使用的是CLSID_DesktopWallpaper的GUID

1 [ComImport]
2 [Guid("C2CF3110-460E-4FC1-B9D0-8A1C0C9CC4BD")]
3 public class DesktopWallpaper
4 {
5 
6 }

5、使用

1 IDesktopWallpaper desktopWallpaper = (IDesktopWallpaper)new DesktopWallpaper();
2 
3 //调用成员函数
4 desktopWallpaper.xxxx();

方法二、自动生成(适用于.NET6+版本)

自动生成主要是借助Cswin32项目来实现这个功能,CsWin32是一个源代码生成器,用于在 C# 项目中添加一组用户定义的 Win32 P/Invoke 方法和支持类型。

CsWin32项目地址:https://github.com/microsoft/CsWin32

这种方法会比较简单方便,但是仅适用于.NET Core。.Net Framework无法使用。

另外还要求Visual Studio的版本至少是Visual Studio 2019 Update 11 (16.11)

使用CsWin32生成COM接口的声明,在官方的文档中并未直接说明,我也是在一个issue中找到了实现方法。

实现步骤如下:

1、nuget导入Microsoft.Windows.CsWin32包

2、在项目下,新建一个NativeMethods.txt文件

3、在NativeMethods.txt下输入需要导入的COM接口

例如我们想使用IDesktopWallpaper接口,就在NativeMethods.txt下输入

1 IDesktopWallpaper
2 DesktopWallpaper 

注意:

1、两个类型都需要写,如果只写了IDesktopWallpaper,就无法实例化接口。我一开始就是卡在这里。

2、需要生成接口的类型都可以写在NativeMethods.txt里,每个类型单独一行。

4、通过代码生成器生成的类型在哪

对于自动生成的类型,命名空间都不一样,但是都是在Windows.Win32命名空间下。

在Visual Studio中,输入Windows.Win32,自己定位所需要类型所在的命名空间即可。

例如IDesktopWallpaper所在的命名空间是:Windows.Win32.UI.Shell

也可以通过Ctrl+T,输入类型名称进行查找 

5、使用

 1             Windows.Win32.UI.Shell.IDesktopWallpaper desktopWallpaper = (Windows.Win32.UI.Shell.IDesktopWallpaper)new Windows.Win32.UI.Shell.DesktopWallpaper();2             Windows.Win32.Foundation.PWSTR pWSTR = new Windows.Win32.Foundation.PWSTR();3            4            5             unsafe6             {7                 char* p = stackalloc char[1];8                 p[0] = '0';9                 Windows.Win32.Foundation.PWSTR szMonitorId = new Windows.Win32.Foundation.PWSTR(p);
10 #pragma warning disable CA1416 // 验证平台兼容性
11                 desktopWallpaper.GetWallpaper(szMonitorId, &pWSTR);
12 #pragma warning restore CA1416 // 验证平台兼容性
13 
14                 MessageBox.Show(pWSTR.ToString());
15             }

说明:CsWin32项目在生成LPWSTR/PWSTR类型时没有使用C#的类型进行映射,例如只读字符串的使用string,需要写入字符串的使用分配空间后的StringBuilder。

所以不得不使用unsafe关键字,并使用指针。这种方法并不太友好 。

示例代码:

 下载

参考资料:

IDesktopWallpaper (shobjidl_core.h) - Win32 apps | Microsoft Learn


http://www.ppmy.cn/embedded/154049.html

相关文章

LabVIEW光流跟踪算法

1. 光流跟踪算法的概述 光流(Optical Flow)是一种图像处理技术,用于估算图像中像素点的运动。通过比较连续帧图像,光流算法可以分析图像中的运动信息,广泛用于目标跟踪、运动检测和视频处理等场景。该示例使用了NI Vi…

Kafka消费者如何优雅下线

一、背景 我们在Kafka消费程序中,可能会调用dubbo接口,也可能会使用线程池,连接池等,但是在服务下线的时候,kafka的消费总是会报错。比如dubbo接口就会抛出异常RpcException: The channel is closed. 这说明kafka还在…

django基于Python的校园个人闲置物品换购平台

Django 基于 Python 的校园个人闲置物品换购平台 一、平台概述 Django 基于 Python 的校园个人闲置物品换购平台是专为校园师生打造的一个便捷、环保且充满活力的线上交易场所。它借助 Django 这一强大的 Python Web 开发框架,整合了校园内丰富的闲置物品资源&…

WEB攻防-通用漏洞_XSS跨站_MXSS_UXSS_FlashXSS_PDFXSS

目录 MXSS攻击 UXSS攻击 FlashXSS PDFXSS MXSS攻击 MXSS,全称“Mutation XSS”,MXSS攻击是一种特殊的XSS攻击类型,简单来说,就是XSS攻击的一种特殊形式,它通过利用网页内容的动态变化或特定条件触发,使…

Golang 并发之 Goroutine

Goroutine 是 Go 编程语言中的一个重要概念。它是 Go 语言实现并发的基础,可以简单地理解为 Go 语言中的轻量级线程。 具体来说,Goroutine 有以下特点: 1.轻量级: Goroutine 的创建和切换都非常快速,只需要几微秒。这与操作系统级别的线程相比要快得多。 2.并发性: Gorout…

工业视觉2-相机选型

工业视觉2-相机选型 一、按芯片类型二、按传感器结构特征三、按扫描方式四、按分辨率大小五、按输出信号六、按输出色彩接口类型 这张图片对工业相机的分类方式进行了总结,具体如下: 一、按芯片类型 CCD相机:采用电荷耦合器件(CC…

【深度学习】PyTorch:手写数字识别

在这个技术博客中,我们将一起探索如何使用PyTorch来实现一个手写数字识别系统。这个系统将基于经典的MNIST数据集,这是一个包含60,000个训练样本和10,000个测试样本的手写数字(0-9)数据库。通过这个项目,你将了解如何使用PyTorch进行深度学习模型的构建、训练和评估。 文…

问题记录-Linux 下.sh脚本中变量不识别-2025-1-14

源文件: CROSS_COMPILE=/opt/cross_chain/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- CC = $(CROSS_COMPILE)g++ 运行 ./auto.sh: line 4: CROSS_COMPILE: command not found ./auto.sh: line 4: CC: command not found 分析: 在 sh 脚本中…