How to call c++ exported method and classes in c#

C++开发基础之创建DLL的常见的6种导出函数(Export Functions)形式 Windows将函数声明和定义分开,使用 __declspec(dllexport) 修饰定义 阅读详情
相对于C++来说,C#是个newcomer,C#提供了一些非常cool的功能,使得我们的工作更加容易。但是,在这个组件横行的年代,如果不懂利用别人写好的代码,就有点落伍了。在C++横行江湖的日子里,留下了很多功能强大的代码,探讨如何在C#的程序中使用这些代码是非常有趣也很有意义的事情,这也是我们今天这篇文章的主题。

  C#是managed code,而C++不是,他们之间的几种交互方式可以用下图表示(今天我们只谈managed code 调用 native code):

  让我们看上图,managed code调用unmanaged code可以采用两种方式,第一种是利用.NET的运行时交互功能(runtime interop facilities),也就是平常看得比较多的P/Invoke(Platform Invoke)或者说DllImport,这种方式用起来比较简单,性能不高,可以用于C风格的dll文件,也可以用于不太复杂的C++类;第二种是手动用managed c++ extensions 封装(wrap)unmanaged c++ class,然后转换成DLL文件,直接加入C#工程的引用集(Refercences)。下面逐条讨论:

第一是使用.NET运行时交互功能的P/Invoke 方式,这又分两个子类:

1. unmanaged code是纯C风格的文件,则直接DllImport即可。
/*Word.dll中有定义好的函数getWord(LPTCHR InputWord)*/
using System.Runtime.InteropServices;//此句必须要,DllImport的namespace
[DllImport("Word.dll",
EntryPoint="getWord",CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
private static extern string getWord(string lex);//declare
public static string getWord(string InputWord)
{
return getWord(InputWord);
}

/*备注:这样就可以了,关于DllImport详细的属性设置或者说明,可以参照MSDN,需要注意的就是设置好与Unmanaged code相对应的数据类型。*/

2. unmanaged code是带有C++类的文件

  一般的做法就是使用托管代码对非托管(unmanaged)C++类进行封装,也就是为其创建一个Wrapper,大致步骤如下:

a) 得到这个非托管类的源代码,这是必需的;

b) 使用C#或者其他任何.NET托管语言创建一个非托管C++类的实例,是不可能办到的。但是要解决这个问题,就需要进行变通。解决方法就是对这个C++类进行扩展,为其创建一个工厂方法(method)(一个静态方法),这个方法必须能够像上面所述的C#调用DLL中的函数那样,能在不创建这个类的实例的前提下,直接被托管代码调用。

c) 使用C#或者其他任何.NET托管语言调用一个非托管C++类的析构函数,也是不可能办到的。因此也需要相应地为这个非托管C++类创建一个可导出供C#调用的静态方法,这个方法的主要任务就是销毁(destroy)类的实例。

d) 对于导出的这个方法,由于不能直接用做Entry point,因此需要使用ordinal作为Entry Point,但是ordinal会随着导入函数的添加或者移除而发生改变,因此使得维护变得比较困难,也容易出现错误。

e) 像上面所述的那样,使用DllImport调用上面实现的导出函数。

这种方法提供了一种比较好的解决方案。我们给个实例

C++ head file
#ifdef PINVOKELIB_EXPORTS
#define PINVOKELIB_API __declspec(dllexport)
#else
#define PINVOKELIB_API __declspec(dllimport)
#endif
// This class is exported from the PinvokeLib.dll
class PINVOKELIB_API CTestClass
{
public:
CTestClass( void );
int DoSomething( int i );
private:
int m_member;
};
extern "C" PINVOKELIB_API CTestClass* CreateTestClass();
extern "C" PINVOKELIB_API void DeleteTestClass( CTestClass* instance );
C++ Body file
#include "stdafx.h"
#include "PinvokeLib.h"
#include <objbase.h>
#include <stdio.h>

BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{ switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// This is the constructor of a class that has been exported.
CTestClass::CTestClass()
{
m_member = 1;
}
int CTestClass::DoSomething( int i )
{
return i*i + m_member;
}
extern "C" PINVOKELIB_API CTestClass* CreateTestClass()
{
return new CTestClass();
}
extern "C" PINVOKELIB_API void DeleteTestClass( CTestClass* instance )
{
delete instance;
}

当使用C# Client调用时,我们只需要编译上述C++文件成DLL,然后使用DllImport即可,如下:

C# code file
using System;
using System.Text;
using System.Runtime.InteropServices;

public class LibWrap
{
[ DllImport( "PinvokeLib.dll",
EntryPoint="?DoSomething@CTestClass@@QAEHH@Z",
CallingConvention=CallingConvention.ThisCall )]
public static extern int TestThisCalling( IntPtr ths, int i );
// CTestClass* CreateTestClass();
[ DllImport( "PinvokeLib.dll" )]
public static extern IntPtr CreateTestClass();
// void DeleteTestClass( CTestClass* instance )
[ DllImport( "PinvokeLib.dll" )]
public static extern void DeleteTestClass( IntPtr instance );
}
public class App{
public static void Main() {
try {
IntPtr instancePtr = LibWrap.CreateTestClass();
int res = LibWrap.TestThisCalling( instancePtr, 9 );
Console.WriteLine( "/nResult: {0} /n", res );
LibWrap.DeleteTestClass( instancePtr );
}
catch(Exception ex) {
Console.Write(ex.ToString());
}
}
}

以上源文件见http://www.cqumstc.net/bbs/dispbbs.asp?boardid=31&id=420

采用wrap方式直接对C++类进行封装,过程如下:

1. 获得unmanaged c++ code

2. 使用managed c++ 对其进行封装(wrap),即使用Win32 DLL将C++ DLL中的导出类进行改写,主要要解决的问题是构造构造函数和析构函数的实现,如下:

首先给出要导出供C#使用的C++类的原型:

C File a.c
/*这是一个基本的C函数,实现了最基本的功能,由b.cpp对他进行封装。 */
char *Word(char *);
char *dir;
int read_dict_info();
/* 注意:在调用Word()之前,必须首先给dir变量赋值,接着才能调用read_dict_info()函数将dir文件夹下面的文件读入。*/
C++ file b.cpp(这个文件里面包含了我们的需要的导出类)
// 一些头文件定义
extern char *Word(char *);
extern char *dir;
extern int read_dict_info();
ClassB::ClassB(string &datadir)
{
dir= new char[datadir.length() + 1];
strcpy(dir, datadir.c_str());
if (read_dict_info())
{
cerr << "Failure reading data files. Check " <<datadir<< endl;
}
}
ClassB::~ClassB() {
delete[](dir);
}
char * ClassB::GetWord(char * word)
{
if (islower(*word))
{
return Word(word);
}
}

按照上面提到的思路,如果要在C#中调用这个类,在不能对ClassB进行实例化的情况下,就需要使用Managed C++对这个Unmanaged C++进行wrap,然后再在C#中调用这个wrapper。

采用本文提到的思路,就可以这样做,具体实现的代码如下: (假设编译出来的DLL名称为Word.dll)

Managed c++ file
//B.h
extern "C" __declspec(dllexport) char * GetWord(char * word);
//B.cpp
// include your header files
extern char *Word(char *);
extern char *dir;
extern int read_dict_info();
char * GetWord(char * word)
{
return Word(word);
}
BOOL APIENTRY DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if( dwReason == DLL_PROCESS_ATTACH ) //等价的构造函数
{
char Datadir[2048];
GetCurrentDirectory(2048,Datadir);
strcat(Datadir, "//dataFiles");
int len=strlen(Datadir);
dir = new char[len+1];
strcpy(dir, Datadir);
if ( read_dict_info())
{
cerr << "Failure reading data files. Check " <<Datadir<< endl;
}
}
if( dwReason == DLL_PROCESS_DETACH ) //等价的析构函数
{
delete[](dir);
}
return true;
}

/*备注:DLL_PROCESS_ATTACH: 进程被调用、DLL_THREAD_ATTACH: 线程被调用、DLL_PROCESS_DETACH: 进程被停止、DLL_THREAD_DETACH: 线程被停止;因此,上面的代码就是利用DLL被调用或者停止时进行构造和析构操作。*/

然后,在C#里面,就可以这样进行调用:

C# File
[DllImport("Word.dll", EntryPoint="GetWord", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.StdCall)]
private static extern string GetWord(string Term);
public static string GetWord(string Term)
{
return GetWord(Term);
}
/*备注:注意对CharSet的设置,如果设置错误,就可能得不到正确的结果。*/

参考文献

1. 在VC编写的DLL中导出C++类
2. HOWTO: Combine managed and Unmanaged Projects into a Single Visual Studio Solution
3. Calling Managed Code from Unmanaged Code and vice-versa
4. Discussion List

 
一种导弹追踪算法的MATLAB仿真实现 以下是一个用于模拟机动变轨导弹和防空导弹追踪过程的 MATLAB 代码,同时会提供 3D 效果展示。你可以运行这段代码,从而观察机动变轨导弹和防空导弹的速度与位置变化。 阅读详情

相关推荐

ffmpeg 4.4 cenc-aes-ctr 加解密 MP4 工程性质分析

ffmpeg 4.4 cenc-aes-ctr 加解密 MP4 工程性质分析

Dream_Dynasty的博客 3045

如何从DLL中导出C++类及接口

 本文粘贴自 CodeProject - HowTo-Export-C-classes-from-a-DLL 。ContentsIntroductionC Language ApproachHandlesCalling ConventionsException SafetyAdvantagesDisadvantagesC++ Naive Approach: Exporting a ClassWha...

weixin_37937630的博客 1768

更多 LSTM 变种——应用于 CMAPSS 数据集

本文并模型介绍,只是把一些比较火的技术,像双向注意力机制,自注意力机制这样的比较火的内容,简单的和LSTM堆叠,结果发现效果都不如最基础的,这里作者将本人代码及实现结果,进行展示,给各位想更改LSTM的朋友一些。

2301_77491330的博客 1765

Export from a DLL Using __declspec(dllexport)

You can export data, functions, classes, or class member functions from a DLL by using the __declspec(dllexport) keyword. If you use __declspec(dllexport), you do not need a .DEF file for exports.

Coder_LCB的博客 522

Proteus 8.17安装部署全指南:避坑、汉化与STM32库配置

Proteus是一款广泛用于单片机仿真与电路设计的EDA工具,其核心价值在于支持嵌入式系统原型验证与教学实践。Proteus 8.17版本重构了许可证机制(LIC Engine)、依赖环境(VC++ 2019/NET 4.8)及路径加载逻辑,导致传统安装方法失效。掌握正确安装部署流程,是保障原理图绘制、VSM仿真(如51/STM32/ESP32)及外设波形观测(OLED、SPI、ADC)稳定运行的前提。本文聚焦Windows平台下零失败安装路径选择、权限配置、汉化实施与高频器件(如STM32F103)元件库

weixin_33377602的博客 402

Isaac Sim 使用经验(配置要求,云服务器)

Google Colab及AutoDL都是在docker内运行,其中google colab并不支持docker指令,而依照AutoDL的相关文档,AutoDL并不直接提供docker指令。2. Google Colab/AutoDL 不支持图形化界面,图形渲染等任务,所以没有办法使用Omniverse Streaming进行直播,从而更好的对结果进行展示。对于第一点,或许存在直接手动复现镜像的可能,但是考虑到Isaac Sim/Isaac Lab由于比较新,可能不够稳定,因此还是按照官方文档进行部署。

weixin_44211433的博客 4587

Balon白话MSDN:从普通DLL中导出C++类(2) – 细看导出C++类的底层机制

 Balon白话MSDN:从普通DLL中导出C++类(2) – 细看导出C++类的底层机制上一篇文章中,我们介绍了怎么从一个DLL中导出C++类,及选择性导出C++类的成员的方法。那么,整个系统的底层机制是怎么样的?是通过什么途径,使得我们可以在另一个程序中使用一个DLL中导出的类的呢?我们知道,要使用一个C++类,必要的条件是在编译期能得到这个类的头文件,并在链接期可以找到对应的符号

程序道 8106

NMS非极大值抑制算法原理

NMS非极大值抑制算法

pywin 3500

C++技巧(用DEF文件从DLL中导出C++类)

用DEF从DLL导出一个函数,或用__declspec(dlleXPort)指令从DLL中导出一类,想必大家已经很熟悉了,也经常使用着。这里向大家介绍一种用DEF文件从DLL导出一个类的方法。具体原理或为什么就不废话了,学会导出后,再慢慢回味吧。这里主要叙述操作步骤。 1.打开VC6.0,新建一个"Win32 Dynamic-Link Library"工程,假设叫DefClass,在“Dll k

痞子龙3D编程 2396

YOLOv11与3D点云检测融合技术深度解析:从2D检测到三维空间投影的完整实现

2D-3D融合目标检测技术研究 本文系统阐述了基于YOLOv11的2D-3D目标检测融合技术,重点分析了YOLOv11在融合系统中的定位优势及其架构设计。研究表明,2D图像与3D点云数据具有显著的互补特性:2D图像提供丰富语义信息,而3D点云则精确描述几何结构。 关键技术要点: YOLOv11通过GSConv平衡卷积和VoVGSCS特征融合模块,在保持实时性的同时提升了检测精度 系统采用模块化设计,包含坐标投影、点云分割、边界框拟合等核心组件 针对点云数据的非均匀分布特性,提出了多尺度特征增强和距离差异化检

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 1126

2020年信奥赛C++提高组csp-s初赛真题及答案解析(阅读程序第3题)

2020年信奥赛C++提高组csp-s初赛真题及答案解析(阅读程序第3题)

王老师青少年编程 990

Exporting a C++ class from a DLL

Adding a simple working example for exporting a C++ class from a DLL : The given below example gives you only a short overview of how dll and exe can interact each other (self explanatory ) but it needs more things to add for changing into a production co

VMLINUZ的专栏 339

【APM】在Kubernetes中,使用Helm安装Grafana 9.5.1

Grafana是一款流行的开源数据可视化和分析平台,它特别擅长处理时序数据,即随时间变化的数据,因此在监控系统性能、应用程序指标、物联网(IoT)设备数据等领域有着广泛的应用。

CN_Eden 1200

【转】How to call c++ exported method and classes in c#

      相对于C++来说,C#是个newcomer,C#提供了一些非常cool的功能,使得我们的工作更加容易。但是,在这个组件横行的年代,如果不懂利用别人写好的代码,就有点落伍了。在C++横行江湖的日子里,留下了很多功能强大的代码,探讨如何在C#的程序中使用这些代码是非常有趣也很有意义的事情,这也是我们今天这篇文章的主题。 C#是managed code,而C++不是,他们之间的几种交互方式可以用下图表示(今天我们只谈managed code 调用 native code): 让我们看上图

云里雾里的专栏 1071

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

dll导出类比较好的方式

看了篇好文,dll导出类的,之前已经胡乱写,以后可以参考这个规范 前言/引用 转自:编写DLL所学所思(2)——导出类 参考:HowTo: Export C++ classes from a DLL 这种方式是比较合适的,跟com类似。结构是这样的: 导出类是一个派生类,派生自一个抽象类——都是纯虚函数。使用者需要知道这个抽象类的结构。DLL最少只需要提供一个用于获取类对象指...

不经一番寒彻骨,怎得梅花扑鼻香。 6032

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

DLL导出函数名

今天想调用一个dll,GetProcAddress返回值总是Null,通过GetLastError,推断是从DLL中找不到函数名,但是函数名明明是正确的,所以查到了以下资料,以供学习。 经常使用VC6的Dependency查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导致不同的原因大多是和编译DLL时候指定DLL导出函数的界定符有关系。 VC++支持两

circle的专栏 2061

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

写C++ DLL时需要写的外部接口头文件

#ifndef WAVELET2D_H #define WAVELET2D_H #include #include using namespace std;       //the dll exports #if defined WAVE_EXPORT #define EXPORT __declspec(dllexport) #else #define EXPORT __

野狼位位的博客 3497

dll 导出函数名的那些事

关键字: VC++  DLL 导出函数  经常使用VC6的Dependency查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导致不同的原因大多是和编译DLL时候指定DLL导出函数的界定符有关系。 VC++支持两种语言:即C/C++,这也是造成DLL导出函数差异的根源 我们用VS2008新建个DLL工程,工程名为“TestDLL” 把默认的源文件后缀 ...

dbtr55989的博客 484

从dll中导出c++类

简介: 动态库(DLL)从开始就作为windows平台的组成部分而存在。它以独立的模块把c函数封装起来供其他用户使用 。DLL从开始就是以封装C语言的形式而存在,当然现在你也可以封装其他语言,比如c++,而如果要实现跨平台使用DLL,则我们必须回归到C语言。 利用C语言接口并不意味着我们必须丢弃掉面向对象方法。C语言可以实现应用二进制接口(ABI),这样使调用者和被调用着可以遵从统一的标准,但

hustshi的专栏 7851

Balon白话MSDN:从普通DLL中导出C++类(1) – dllexport和dllimport的使用方法(中英对照、附注解)

 这几天写几个小程序练手,在准备将一个类导出时,发现还真不知道如果不用MFC的扩展DLL,是怎么导出的。但我知道dllexport可以导出函数和变量,而且MFC扩展DLL就算是使用了MFC的功能,但能否导出类应该也不是必须用MFC才能够做到,一定是有相应的机制可以实现。于是查了一下MSDN,发现这个机制简单的可怕,原来就和导出函数一样,把dllexport关键字加到类名前就可以了。估计和我一样的同

hxb20082008的专栏 2877

VC++动态链接库(DLL)编程深入浅出(zz)

1.概论  先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。在仓库的发展史上经历了“无库-静态链接库-动态链接库”的时代。  静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。但是若使用DLL,该DLL不必...

weixin_33755554的博客 641

HowTo: Export C++ classes from a DLL

HowTo: Export C++ classes from a DLL By Alex Blekhman, 13 Nov 2012   4.91 (119 votes)   Download source - 11.1 KB Contents Introduction

石头 1084

Exporting C++ classes from a DLL

Exporting C++ classes from a DLL 这个文章中的内容和之前的文章中的内容是一致的意思,核心思想是在创建动态库的时候创建一个重虚函数类作为基类接口使用,而在exe中使用这些接口来访问动态库中对这些基类重写的函数,从而达到访问动态库的内容的目的。 目前个人对此问题的理解为:主要是C++中对编译器对代码进行编译之后,函数名称发生变化,跟C相比,C代码中的函数的名称在编译

OpenWrt/WLAN/驱动/Android/嵌入式开发总结 1239

(转)怎样从一个DLL中导出一个C++类

原文作者:Alex Blekhman 翻译:朱金灿 原文来源: http://www.codeproject.com/KB/cpp/howto_export_cpp_classes.aspx 译文来源:http://blog.youkuaiyun.com/clever101/article/details/3034743 C++语言毕竟能和Windows D...

weixin_30345055的博客 564

【C++笔记 】如何从DLL中导出一个c++类

文章目录前言方法1:C Language Approach(C语言方式)方法2:Naive Approach(导出c++类)方法3:Mature Approach(用抽象c++接口) 前言 工作中遇到需要从DLL中导出类,查阅了相关博客资料,进行了部分总结。 参考连接: https://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL 文中包含两个工程: XyzLibrary —— 一个DLL工程; XyzExecuta

muyijames的博客 1667

C++ DLL导出类

C++ DLL导出类 http://blog.youkuaiyun.com/jietoulangren/article/details/14052533 在公司使用C++ 做开发,公司的大拿搭了一个C++的跨平台开发框架。在C++开发领域我还是个新手,有很多知识要学,比如Dll库的开发。    参考了很多这方面的资料,对DLL有一个基本全面的了解。有一个问题让我有点困惑,普通的导入导出C++类的方式

优快云Microsoft优快云的专栏 4777
上一篇: 对 Windows 窗体控件进行线程安全调用
下一篇: 反射与属性
RedRiver331
博客等级 码龄24年 1粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值