C#与C++代码的互操作方式

这篇具有很好参考价值的文章主要介绍了C#与C++代码的互操作方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

title: C#与C++代码的互操作方式
date: 2024-01-10
categories: 编程
tags:
- C#
- .NET
- C++
- COM
- 平台调用

大致介绍

在写C#程序时经常有与本地代码(C/C++)代码交互的需求。微软提供了许多种方式供我们选择,
最常用的有以下三种(A->B指A可以引用B):

flowchart LR A--P/Invoke-->B A<--C++ Interop-->C A<--COM Interop-->D D<-->C-->B subgraph 托管环境 A[.NET应用程序] end subgraph 非托管环境 B[C 库函数] C[C++ 类库] D[COM组件] end
  • P/Invoke (Platform Invoke):平台调用,是一种用于和非托管函数进行交互的技术,
    在调用Windows API的时候有大量的运用。特点是无需编写兼容层代码即可使用。
  • C++ Interop:托管C++,使用C++/CLI (Common Language Infrastructure)语言,
    特点是可以将托管代码和非托管代码写在一个文件/程序集里,从而使得它十分灵活,它本质上还是平台调用。
  • COM (Component Object Model):组件对象模型,是微软早在.NET出现之前就提出的一种Windows开发技术,
    现在Windows中到处都有它参与。虽然它是很老的技术,但在最新的技术中也可以看到它的身影(如WinUI3)。
    需不需要写兼容层代码取决于原来的代码有没有使用COM,如Win32就没有使用,而WinRT使用了。

那么如何从这之中选择呢?以下列出了三种方式的大致区别:

P/Invoke C++ Interop COM Interop
支持平台 全平台 仅Windows 理论上全平台
语言 标准C/C++ C++/CLI IDL
导出对象 函数
引用方式 DllImport 直接引用 ComImport
上手难度 几乎无难度 简单 复杂
兼容层代码 不需要 需要 可能需要

性能测试

选择一种技术最重要的指标就是效率了,我测试了三种技术分别在大量调用、大量执行次数情况下的表现情况。
调用次数是由托管代码实现的(即调用Test的次数),执行次数是由本地代码实现的(即传入的参数executions)。
我选择了IsWindows10OrGreater函数进行调用测试:

HRESULT Test(int executions)
{
    for (int i = 0; i < executions; ++i)
    {
        IsWindows10OrGreater();
    }
    return S_OK;
}

源代码可以参见仓库[1]
我在Windows11 64位系统下运行,使用.NET 8运行时,以下是测试结果:

调用/执行次数 P/Invoke C++ Interop COM Interop
1000000/1 01.162s 01.327s 32.504s
1/1000000 01.054s 01.294s 01.063s

可见除了大量调用COM,其他的方法效率都差不多。这是因为每次调用COM都会产生一个COM对象,
从而导致速度很慢。三种方法都有类型封送(Marshal)操作,这也是最花时间部分,所以使用时间都差不多。
可以从下面流程图了解大致流程:

P/Invoke流程图

flowchart LR B-->C-->F--平台调用<br/>封送处理-->G D~~~E subgraph 非托管 subgraph G[DLL] A[非托管函数] end end subgraph 托管 B[托管源代码] C[编译器] subgraph CLR subgraph F[程序集] direction TB D[元数据] E[IL代码] end end end

COM流程图

flowchart LR X--IDispatch---F Y--ISimpleCOMCalculator---F Z--IUnknown---F A-->B C-->D-->B-->E-->Y subgraph 托管代码 A[托管应用程序] B[元数据代理] C[COM组件类型库] D([类型库导入程序<br/>TlbImp.exe]) end E[运行库课调用包装<br/>RCW] subgraph 非托管COM代码 F[COM对象] X(( )) Y(( )) Z(( )) end

个人看法

P/Invoke的两端是标准的C/C++和标准的C#(.NET)代码,是保持可移植性、可读性的不二之选。
平台调用流程相对简单,过程更加透明,在绝大多数情况下都应该选择它。
但它的缺点是无法导出类,如果大型项目有面对对象的需求(类似于DirectX)则不是最优选择。

C++ Interop灵活性非常高,可以准确控制封送过程,所以性能理论上也更好。
但是缺点[2]也更严重,它只能面向Windows平台,
很多情况下这个缺点是不能接受的。如果目标项目是只面向Windows平台(如WinForm,WPF等),
且要调用大量本地API,而且对性能要求较苛刻的情况下,可以考虑使用。

COM有着很复杂的内部结构,学习成本较高。如果写小型项目,即使有面向对象的需求也不需要使用它。
但如果接触Windows平台编程,几乎绕不开调用COM,所以也要对调用COM代码有一定程度的了解。
同时也要避免创建大量COM对象,这可能导致性能低下。

可以参考《精通.NET互操作 P/Invoke,C++Interop和COM Interop》[3]这本书来学习。


  1. InteropPerformanceTest ↩︎

  2. C++/CLI .NET Core 限制 ↩︎

  3. 《精通.NET互操作 P/Invoke,C++Interop和COM Interop》 黄际洲 崔晓源 著 ↩︎文章来源地址https://www.toymoban.com/news/detail-788588.html

到了这里,关于C#与C++代码的互操作方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C#操作Excel文件三种方式

    C#操作Excel文件三种方式 彭世瑜2021-07-12 16:14:28 文章标签C/C++文章分类C/C++后端开发阅读数5317 .Net平台上对Excel进行操作主要有两种方式。第一种,把Excel文件看成一个数据库,通过OleDb的方式进行读取与操作;第二种,调用Excel的COM组件。两种方式各有特点。 注意一些简单的问

    2024年02月15日
    浏览(39)
  • C#操作Excel文件三种方式详解

    1.OleDb方式: 使用.NET Framework内置的System.Data.OleDb命名空间中的类,可以将Excel文件当作数据库来读取数据。这种方式适用于较旧版本的Excel文件(.xls格式,即Excel 2003及更早版本)。 2.COM组件方式: 利用Office Interop库(如Microsoft.Office.Interop.Excel),可以直接调用Excel应用程序的

    2024年03月18日
    浏览(58)
  • 【微软技术栈】与其他.NET语言的互操作性 (C++/CLI)

    使用 C# 索引器 实现 C# 的 is 和 as 实现 C# 的 lock 本节中的主题介绍如何在 Visual C++ 中创建程序集,这些程序集使用或提供以 C# 或 Visual Basic 编写的程序集的功能。 Visual C++ 不包含索引器;它具有索引属性。 若要使用 C# 索引器,请访问索引器,就像它是索引属性

    2024年02月03日
    浏览(60)
  • C#调用C++类,托管C++方式实现(创建C++ CLR dll项目)

            由于C#编写的是托管代码,编译生成微软中间语言,而C++代码则编译生成本地机器码(这种C++也有叫做本地C++或者非托管C++,VC6.0就是用于开发非托管C++代码的平台),这两种语言进行混合编程就存在一定困难。比较常用的方法是使用DllImport的方法,这种方法在网

    2024年02月07日
    浏览(47)
  • Js水几个基础知识点:数组的操作,字符串和数组之间的互转,持续补充,欢迎关注

    一、插入 / 删除元素: 我们就不从创建开始讲了,那个太基础了,js创建数组一般都直接let arr = […,…,…],有部分仁兄喜欢new Array(…, …, …),这样看起来可能高级点,结果是一样的哈。 这里我们直接来讨论插入元素: 1、在末尾插入 / 删除元素(push / pop,操作原数组)

    2024年02月09日
    浏览(59)
  • Winform中实现窗体控件适配(自适应窗体)布局_通过C#代码方式

    即:未启用控件缩放效果代码时,控件内容都是固定在窗体界面的指定位置,不会跟随窗体的拉伸,放大而进行适配,如下图所示: 即:启用控件缩放效果代码时,控件内容会跟随窗体的拉伸,放大而进行适配,如下图所示: 实现思路是: ①在窗体初始化时先获取窗体的宽

    2023年04月17日
    浏览(48)
  • 【Unity框架】XLua中Lua代码注入C#代码操作

    1.游戏框架下载地址:https://github.com/kof123w/gitWorkSpace/tree/main/XLua 2.XLua官方与教程地址:https://github.com/Tencent/xLua I.宏定义:添加 HOTFIX_ENABLE 到 Edit Project Settings Player Other Settings Scripting Define Symbols II.生成代码:执行 ‘XLua Generate Code’ 菜单,等待Unity编译完成 III.注入:执行 ‘XLua

    2024年02月08日
    浏览(62)
  • C#用dynamic一行代码实现反射操作

    dynamic简介 dynamic是.NET Framework4.0的新特性。dynamic的出现让C#具有了弱语言类型的特性。编译器在编译的时候不再对类型进行检查,编译时默认dynamic对象支持你想要的任何特性。 dynamic简化反射实现 使用dynamic来简化反射实现是一种比较常见的编程技巧,它可以减少代码的复杂性

    2023年04月24日
    浏览(30)
  • c# 代码操作ftp服务器文件

    好久不见,我又回来了。给大家分享一个最近c#代码操作ftp服务器的代码示例   基础类的构造函数和属性       FtpOperation 中其他的方法 调用示例  贴了半天代码,都不太行,一会能展开,一会展不开,源码地址放下面了。 项目地址:https://github.com/yycb1994/FtpSiteManager

    2024年02月21日
    浏览(45)
  • c++ 继承方式高内聚read write function操作

    派生类增加传入指定函数

    2024年02月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包