VC 调用托管程序集(.Net Managed Assemblies)

[VC++ .NET编程]托管C++基础 空 阅读详情

前言

.Net 类库功能非常全面分装了大量应用级别的API,所以有时会有在VC 中调用托管程序集(.Net Managed Assemblies) 的需求。本文通过示例对该步骤进行说明,并提供一些参考。

前提

本文假设已有一个现成可用的托管程序集,代码如下:

// 媒体类:用来载入一个媒体文件,并解析出信息
public class Media
{
	// 内部处理
	private void DoSomething()
	{ ... }

	// 载入文件	
	public void LoadMedia(string filePath)
	{ ... }

	// 获取媒体信息
	public MediaInfo GetInfo()
	{ ... }
}

// 媒体信息类
public class MediaInfo
{
	// 内部标示
	private Guid id;
	// 文件名
	public property string Name { get; set; }
}

托管程序集(.Net Managed Assemblies)

1 追加 ComVisible Attribute

要使一个托管程序集能作为 COM 被 VC 调用首先需要添加 ComVisible Attribute。如果你比较懒可以在项目的 AssemblyInfo.cs 文件中进行全局声明:

[assembly: ComVisible(true)]
[assembly: Guid("2aa76d89-5faf-473e-8285-b9199fedd365")]

当程序集的公有类相当多的时候这是个好办法,但是并不建议这样做,因为调用方(VC)通常并不需要访问程序集中的所有公有类,并且过多的暴露程序集也不太好。这里我们就勤劳点,在每个类上进行声明。

[ComVisible(true)]
public class Media : IDisposable
{
	// 略
}

[ComVisible(true)]
public class MediaInfo
{
	// 略
}

2 追加 ClassInterface Attribute

参照一下 MSDN 该 Attribute 需要传入一个 ClassInterfaceType 枚举来决定生成接口的方式:

  • AutoDual 指示自动为类生成双重类接口并向 COM 公开。为该类接口生成类型信息并在类型库中发布。由于 ClassInterfaceAttribute 中描述的版本控制方面的限制,极力建议不要使用 AutoDual。
  • AutoDispatch 指示该类只支持 COM 客户端的后期绑定。在请求时,该类的调度接口将自动向 COM 客户端公开。类型 类型库导出程序 (Tlbexp.exe) 生成的类型库不包含调度接口的类型信息,以防止客户端缓存接口的 DISPID。由于客户端只能后期绑定到调度接口,因此该接口不会出现 ClassInterfaceAttribute 中所述的版本控制问题。
    这是 ClassInterfaceAttribute 的默认设置。
  • None 指示不为类生成类接口。如果未显式实现任何接口,则该类将只通过 IDispatch 接口提供后期绑定访问。这是 ClassInterfaceAttribute 的推荐设置。

既然官方推荐,那么我们就采用ClassInterfaceType.None,但是因为类接口不再自动生成,所以我们需要自己为 2 个类分别定义 2 个接口:

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(IMedia))]
public class Media : IDisposable, IMedia
{
	// 略
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class MediaInfo : IMediaInfo
{
	// 略
}

[ComVisible(true)]
public interface IMedia
{	
	void LoadMedia(string filePath);
	MediaInfo GetInfo();
}

[ComVisible(true)]
public interface IMediaInfo
{
	property string Name { get; set; }
}

提示:

  • 接口只需要定义公开给 Com 的接口,即如果VC 不需要调用 LoadMedia 方法,那么IMedia 接口中可以不包含该方法
  • 接口本身也需要 ComVisible 声明
  • 当某个类实现了多个接口的情况下,需要使用 ComDefaultInterface 明确指定 COM 接口是哪一个

3 生成支持 COM 调用托管程序集(.Net Managed Assemblies)

使用 VS 的话相当简单,在工程的属性页面里“Register for COM interop”打个钩就一切搞定,编译后去 bin 下面就能找到 .NET 程序集,以及一个同名的 .tlb 文件。

当然你也需要了解下怎样使用命令行工具来实现,毕竟配布到用户机上时会用到。这里介绍下程序集注册工具 (Regasm.exe),VS 实际上帮我们运行了以下命令:

regasm myTest.dll /tlb:myTest.tlb

MSDN 官方描述为:注册 myTest.dll 中包含的所有公共类,并生成和注册类型库 myTest.tlb,该类型库包含 myTest.dll 中定义的所有公共类型的定义。

COM 类注册自然是更新注册表了,那配布的时候用户机上同样需要更新注册表,那么怎样知道需要更新哪些信息呢?Regasm.exe 会告诉你:

regasm myTest.dll /regfile:myTest.reg

这个命令会生成一个注册表文件,需要更新的内容都在里面了。好了该说 VC 怎样调用了。

VC 调用托管程序集

方便起见我们用空的一个命令行 VC 工程来说明步骤。

1 添加 import 声明,并生成 com 接口

在 .cpp 文件中添加以下内容并编译(生成物中会包含一个 .tlh 的头文件):

#import "myTest.tlb" named_guids raw_interfaces_only

PS:这里的文件路径可以是绝对路径,也可以是相对路径。

如果你还引用到一些 .NET 类库中的类型那么也需要追加 import 声明,譬如使用了 System.Drawing 中的类型,那么要追加:

#import "C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Drawing.tlb" named_guids raw_interfaces_only

2 代码调用

HRESULT hRes;
hRes = CoInitialize(NULL);	// 初始化 Com

MyTest::IMediaPtr pIMedia(__uuidof(MyTest::Media));		// 使用智能指针实例化对象

pIMedia->LoadMedia(::SysAllocString(L"d:\\aaa.png"));		// 调用方法,OK

MyTest::IMediaInfoPtr pIMediaInfo = pIMedia->GetInfo();		// 调用方法并返回值,NG

CoUninitialize();	// 终止初始化 Com

调用没有返回值的方法时一切正常,调用有返回值的方法时你会发现函数定义被改写了,这是什么情况?原来从 .NET 程序集转换为 com 时,如果有返回值,这个返回值将作为ref参数追加在该函数之后,而返回值会用来返回 HRESULT。这虽然没啥大问题,但用起来却大大的不爽,想用回原来调用方式的情看下文。

托管程序集(.Net Managed Assemblies)再修改

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(IMedia))]
public class Media : IDisposable, IMedia
{
	// 略

	[PreserveSig]
	public MediaInfo GetInfo()
	{ ... }
}

PreserveSig 可以保证转换的 com 接口不改写原来的方法定义,详细请看http://msdn.microsoft.com/zh-cn/library/system.runtime.interopservices.dllimportattribute.preservesig(v=vs.80).aspx

现在我们再次编译 .NET ,打开 VC 工程,并确认两个方法都能正确调用了。

在 Visual C++/Native 代码中调用.NET 程序集 在本地 Visual C++中基本上有四种方法可以调用.NET程序集。微软的All-In-One Code Framework  All-In-One Interop and Fusion Code Samples有一些可以工作的例子来说明这个问题。 1.本地 VC++模型调用CLR Hosting APIs来托管CLR,加载并调用.NET程序集,该方法也被用来保护.NET程序(套一 阅读详情

相关推荐

Grasshopper 二次开发 (C#) Part 5 - Tricks, 5.3 使用 C# 调用 Grasshopper 内的组件

本博客内容正在持续更新,最后一次更新时间:2020.09.04 【说明】 1.本专栏的 Part 5 主要介绍作者在学习和实践中所遇到的一些问题的解决方案,如有差错或更优解,欢迎指正 2.您如果碰到有关 GH 二开的任何问题,欢迎在本专栏的任意一篇博文下留言交流 【本文重点】 1.查文档:(1) RhinoCommon SDK (2) Grasshopper API 2.专栏地址:专栏:Rhino (Grasshopper) 二次开发 (C#) 【推荐阅读】 1.有关 Grasshopper 部分知识点和操

weixin_43728138的博客 3987

在VS 2005中使用托管C++需要的配置

clr配置:   1. 打开此项目的“属性页”对话框。    2. 单击“配置属性”文件夹。    3. 单击“常规”属性页。    4.在“项目默认值”中将“ 公共语言运行库支持”改为“公共语言运行库支持,原来的语法 (/clr:oldSyntax)。” 

youganquan的专栏 620

BMS开发避坑指南:如何用ADBMS6815实现0.03%精度的电池采样?

本文深入解析了如何利用ADBMS6815等高精度AFE芯片,在车规级BMS开发中实现0.03%级别的电池电压采样精度。文章从芯片选型、硬件设计、软件配置、算法优化到系统验证,提供了一套完整的实战指南,帮助工程师系统性地提升BMS测量精度,从而保障电池安全、延长寿命并增强产品竞争力。

weixin_28314575的博客 134

C++调用托管dll的两种方法

VisualC、Delphi或者VB等编程语言来编写的DLL文件,在编译完成以后,产生DLL文件已经是一个可以直接供计算机使用的二进制文件,而Visual C#生成的DLL不是独立运行的程序,是某个程序的一个部分,只能由所属的程序调用,用户不能也不需要打开它,Visual C#编译器生成的托管代码虽然也是二进制文件,但不是可以直接供计算机使用的原始代码,实际上是一种中间语言(IL)代码,需要经

sundk911的专栏 5075

别再到处找包了!Keil5芯片支持包(Pack)最全管理指南:安装、更新、迁移与离线备份

本文详细解析了Keil5芯片支持包(Pack)的全生命周期管理,包括安装、更新、迁移与离线备份的工程化解决方案。针对STM32F10x等常见芯片,提供了高效获取Pack的策略、版本管理技巧及团队协作方案,帮助开发者解决常见的'Device Family Pack missing'等问题,提升嵌入式开发效率。

weixin_28729205的博客 539

ESP32 驱动 SYN6288 语音合成:Arduino IDE 下实现中文数字混合文本的智能播报

本文详细介绍了如何在Arduino IDE环境下使用ESP32驱动SYN6288语音合成模块,实现中文数字混合文本的智能播报。通过硬件选型、开发环境搭建、编码转换原理、命令帧构造及串口通信实战等步骤,帮助开发者快速掌握语音播报技术。文章还提供了混合文本处理技巧和常见问题排查方法,适合智能硬件开发者参考。

weixin_42553471的博客 447

vc托管调用c#dll

众所周知,c#编译器编译代码为托管代码,可以使用vs自带的返编译工具查看代码结构,而vc不但能够编译非托管代码,使得不能被反编译,它又能编译托管代码,不过新建工程的时候默认的是非托管代码。这样一来在vc中调用c#编译出来的dll文件就会产生一些问题: fatal error C1190: 托管目标代码需要“/clr”选项 可以更改环境配置进行解决:属性->配置属性->常规->公共语言运行时支持

净土 4699

医学图像分割评价指标详解:从Dice到MSD的实战解析

本文深入解析医学图像分割的核心评价指标,从最常用的Dice相似系数到衡量边界精度的MSD(最大对称表面距离),通过实战案例与代码演示,系统阐述各指标的计算原理、应用场景及临床意义,帮助读者全面评估模型性能。

weixin_29070721的博客 593

Win32程序如何调用.net DLL

1、建立:DotNetFunc.cs 封装要使用的Function、Procedure。2、生成密钥文件,用于给程序集强名称签名sn -k key.snk 3、使用强名称签名,编译成类库csc /t:library DotNetFunc.cs 4、生成类型库tlbexp DotNetFunc.dll /out:DotNetFunc.tlb 5、注册dllregasm DotNetFunc.dll 6、移入gac全局程序集缓存gacutil -i DotNetFunc.dll 

木桌的技术博客 952

YooAsset 2.2.12四层加密架构:跨平台资源安全实战指南

AssetBundle加密是Unity热更新安全的核心环节,其本质是通过算法、密钥管理与生命周期协同实现资源全链路防护。传统方案常陷于‘打包后加密’的误区,导致内存开销大、跨平台兼容差、逆向防护弱。YooAsset 2.2.12提出打包层、传输层、加载层、运行层四层防护架构,将加密前置到资源序列化前,并依托BundleHeader实现动态算法协商与密钥分发,显著提升iOS/Android/WebGL三端一致性。该方案兼顾AES-128等通用算法与SM4等国密支持,同时通过IMemoryDecryptor实现

weixin_32428571的博客 414

实用电路精讲系列---双级运放放大电路(差分放大+跟随缓冲)

本文分析了双极运放放大电路的工作原理及其典型应用。该电路结合差分放大器和跟随缓冲器,实现高精度信号放大与阻抗匹配。差分放大器通过放大差模信号并抑制共模噪声提升信噪比;跟随缓冲器则提供阻抗变换,确保信号稳定传输。两者协同工作可优化输入阻抗、增强噪声抑制并提高设计灵活性。文章还列举了10个典型应用案例,包括医疗设备、工业传感器和新能源系统等,展示了该电路在精密电子系统中的关键作用。最后通过实用电路分析,详细说明了各模块功能及设计注意事项。

weixin_40590799的博客 2951

在 C# 中创建 COM 对象 (把 C# 类公布到 COM )

所谓在 c# 中创建 com 对象,实际上就是向 com 公开用 c# 编写的组件对象接口。这个 c# 类及其成员必须遵循下列规则才能对 com 可见:1> 类必须是公共的。 2> 属性、方法和事件必须是公共的。 3> 属性和方法必须在类接口上声明。 4> 事件必须在事件接口中声明。 其他没有在这些接口中声明的类的公共成员对于 com 是不可见的,但它们对于其他 .net framewor

大鸾翔宇,遨游苍穹! 1619

高通平台Android稳定性调试笔记:手把手教你用T32、Crash Utility分析Kernel Panic与RAM Dump

本文详细介绍了高通平台Android内核崩溃的分析方法,包括使用T32 Simulator和Crash Utility工具链解析Kernel Panic与RAM Dump。从环境配置、dump文件预处理到高级调试技巧,手把手教你如何定位和解决Android系统崩溃问题,特别适用于MSM/SA8155平台的开发者。

weixin_42543046的博客 525

ClassInterface

ClassInterface 类接口是未在托管代码中显式定义的接口,它将公开在 .NET 对象上显式公开的所有公共方法、属性、字段和事件。此接口可以是双绑定接口,也可以是仅调度接口。• ClassInterfaceType.None • ClassInterfaceType.AutoDispatc • ClassInterfaceType.AutoDual N...

684

详解AUTOSAR:专栏总述

本专栏系统介绍AUTOSAR规范及车用控制器软件开发,内容覆盖基础架构、SWC/RTE、通信栈、诊断、存储、安全、看门狗、工具链、环境配置与项目实战,并持续更新各模块的集成机制与工程要点。

不脱发的程序猿 3917

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Introducing the Class Interface

Introducing the Class InterfaceThe class interface, which is not explicitly defined in managed code, is an interface that exposes all public methods, properties, fields, and events that are ex

瞎掰大数据-- 世界的本质是数据,胡侃瞎掰,专注微软大数据解决方案 858

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

[VC.NET]托管代码和非托管代码

转载: 所谓托管是指内存管理由系统而不是由程序员管理。 像C#这样的语言的内存管理(内存的分配和释放)都是由系统管理的。所以只有new而没有delete。 C++有个很重要的特点就是内存由程序员管理。所以分配内存以后,要程序员自己释放。如果没有释放就会有内存泄露,如果在不该释放时释放了,就会出现所谓的野指针。 在C++把内存管理交给系统的,由系统来负责释放,就被称为托管。 托管C++

Russius的博客 1085

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

VC++调用C#dll库

1、创建C# COM 库项目以管理员身份运行VS。鼠标右击打开这个菜单。用vs2022创建.net framework库项目设置项目:打开项目属性:点程序集信息按钮使程序集COM可见前面打勾。按确定按钮后选生成选项:在下面的“为COM互操作注册”前打勾。目标平台选x64。生成项目。2、创建VC++ 项目创建MFC项目,如果没有看到MFC选项,则要安装。创建后应用程序类型选基于对话框项目创建好以后,先进行设置。

ywqb95的博客 268

ArcEngine 移除当前图层

/*************************** Write by Chn gzGISer Tst 优快云 blog Ricardo.M.Tan **************************/ using System; using System.Runtime.InteropServices; using ESRI.ArcGIS.ADF.BaseClasses; usi...

Birds-Frags's Blog 1898

C#错误和异常(五)自定义异常类

C#自定义异常类 在介绍自定义异常类之前我们先看看C#中的默认System.Exception类的元数据。 // 摘要: // 表示在应用程序执行过程中发生的错误。 [Serializable] [ClassInterface(ClassInterfaceType.None)] [ComDefaultInterface(typeof(_...

weixin_40786497的博客 1517

如何判断程序集是Managed Assembly

//https://blogs.msdn.microsoft.com/kstanton/2004/03/31/exploring-pe-file-headers-using-managed-code/ public static bool IsManagedAssembly(string assemblyFilePath) {

Eco-dream‘s CODE World 998

类接口/Class Interface

在查看Object类的定义时发现Object使用了ClassInterface,而且是ClassInterfaceType.AutoDual故查看一下具体什么,原来是类接口是为互操作而设计的,其中写到托管代码中基类或接口的中顺序也会影响互操作,真是不应乱该动代码。:) 类接口是未在托管代码中显式定义的接口,它将公开在 .NET 对象上显式公开的所有公共方法、属性、字段和事件。...

weixin_30443813的博客 1709

ComInterfaceType

using System; namespace System.Runtime.InteropServices { [ComVisible (true)] [Serializable] public enum ComInterfaceType { InterfaceIsDual, InterfaceIsIUnknown, InterfaceIsIDispatch } }

heyuchang666的专栏 1201
上一篇: .NET Reflection optimization 反射优化
下一篇: 何时使用 Parallel.ForEach,何时使用 PLINQ
sqlchen
博客等级 码龄24年 10粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值