首页 > 编程语言 >C#与C++动态链接库DLL参数互传

C#与C++动态链接库DLL参数互传

时间:2023-07-28 17:56:05浏览次数:36  
标签:C# C++ char 互传 result 类型 TestDll

C#与C++动态链接库DLL参数互传
一、C#中导入C++动态链接库
二、C#传入字符串参数
三、C++传出字符串参数
四、C++传出vector
一、C#中导入C++动态链接库
从界面程序开发的角度来说,C#语言效率较C++高,且通过WPF开发出的程序界面更为美观,但在开发实际项目中有时不可避免的需要使用C++程序库,通常的做法是将C++程序编译为动态链接库,及DLL文件,然后在C#中进行导入调用。
导出C++程序通常的做法是使用_declspec(dllexport) /_declspec(dllimport)来导入导出,C++示例代码如下:

#include <iostream>
using namespace std;
extern "C" _declspec(dllexport) void TestDll(char* Path, char* result);
_declspec(dllexport) void TestDll(char* Path, char* result)
{
***//函数功能具体实现
}
以VS2019中编译Dll为例,打开项目属性窗口,点击配置属性——常规,将配置类型选择为动态库(.dll),然后点击配置属性——高级,将目标文件扩展名选择为.dll,然后设置好解决方案配置和平台后生成dll文件。

导出为Dll文件后,例如导出文件名为TestDll.dll,在C#中调用示例代码如下:

[DllImport("TestDll.dll", EntryPoint = "TestDll")]
static extern void TestDll(string Path, [Out, MarshalAs(UnmanagedType.LPArray)] char[] result);
下面具体讲如何在C#与C++之间实现参数传递。

二、C#传入字符串参数
参数传递主要涉及C#调用dll文件时传入dll参数和调用结束dll文件传出参数。通常传入dll的参数类型为整数类型,整数数组类型和字符串类型。在C#和C++中整数类型通常都为int类型,在参数传入时直接传入即可。但对于字符串类型,C#中为string类型,而C++中通常是使用字符数组来存储字符串,即char[]或char*类型,而C++中也使用std::string类型来存储字符串,但在实际使用过程中发现当C++中接收参数类型是该类型时会报出错误,示例代码如下:

//C++代码
#include <iostream>
using namespace std;
extern "C" _declspec(dllexport) void TestDll(char* Path);
_declspec(dllexport) void TestDll(char* Path)
{
***//函数功能具体实现
}

//C#代码
[DllImport("TestDll.dll", EntryPoint = "TestDll")]
static extern void TestDll(string Path);
string path = "hello";
TestDll(path);

上述代码中,C#传入字符串类型为string类型,而C++接收参数类型为char*类型,经实际测试,中文字符和英文字符都可以正确传输。

三、C++传出字符串参数
C++传出字符串参数较C#传入更为复杂,因C++中字符存储是以指针形式,所以可以通过如下方式来实现:C#传入一个数组参数,传入后C++对该数组指针进行赋值,然后传出。
实现方式有两种,一种为C#传入char数组类型,一种为C#传入byte数组类型,示例代码如下:

//C++代码
#include <iostream>
using namespace std;
extern "C" _declspec(dllexport) void TestDll(char* result);
_declspec(dllexport) void TestDll(char* result)
{
char s[20]="hello";
memcpy(result, s, strlen(s));
}
memcpy为C++内存拷贝函数,使用时需要注意strlen与sizeof函数的区别,两者都是获得变量的字节数,不同的是strlen只适用于char*类型,当遇到’\0’字节时停止计数,而sizeof适用于多种类型和对象,当用于数组类型时获得的时初始化时分配的字节数,而不是实际使用的字节数。

//C#代码
[DllImport("TestDll.dll", EntryPoint = "TestDll")]
static extern void TestDll([Out, MarshalAs(UnmanagedType.LPArray)] char[] result);
char[] result = new char[100];
TestDll(result);
string re = new string(result);
Console.WriteLine(re);

在C#中传入char[]即字符数组类型,待C++中对result赋值完成后再取出result,对字符串re赋值,这样就实现了C++字符串参数的传出。需要注意的是在C#中数组是直接使用的,而在C++中返回的是数组的指针,[Out, MarshalAs(UnmanagedType.LPArray)]用来转化这两种不同的类型。
上述实现方式为传入char数组类型方式,但如果C++传出的字符串包含中文字符,那么可能在C#中会显示乱码,因为中文字符为UTF-8编码。下面介绍使用byte数组方式,C++中代码不变,C#中代码如下:

//C#代码
[DllImport("TestDll.dll", EntryPoint = "TestDll")]
static extern void TestDll(ref byte t);
byte[] t = new byte[100];
TestDll(path, ref t[0]);
string re = Encoding.UTF8.GetString(t);
Console.WriteLine(re);

byte数组方式传输中文字符不算出现乱码情况。

四、C++传出vector<char*>参数
vector类型为C++中类似于列表的数据类型,能够自由添加、插入、删除元素,与C#中List类型功能相似。但当要在C++传出vector类型时,在C#端的接收数据类型却不能为List,否则会报出错误,而应该使用C#中的IntPtr类型,示例代码如下:

//C++代码
#include <iostream>
using namespace std;
extern "C" _declspec(dllexport) void TestDll(int& num, char** &result);
_declspec(dllexport) void TestDll(int& num, char** &result)
{
std::vector<char*> res;
char* tmp = new char[5];
char s[20]="hello";
memcpy(tmp, s, strlen(s));
res.push_back(tmp);
num = 1;
result = res.data();
}

在上述C++代码中主要通过res.data()函数实现将vector<char*>类型转换为char**类型,从而方便C#端读取,而num变量而表示vector类型的元素个数,C#端代码如下:

//C#代码
[DllImport("TestDll.dll", EntryPoint = "TestDll")]
static unsafe extern void TestDll(ref int num, ref IntPtr t);
int num = 0;
IntPtr data = IntPtr.Zero;
TestDll(ref num, ref data);
for (int i = 0; i < num; ++i)
{
int size = Marshal.SizeOf(typeof(IntPtr));
IntPtr intPtr = Marshal.ReadIntPtr(data, size * i);
string datastr = Marshal.PtrToStringAnsi(intPtr);
Console.WriteLine(datastr);
}

C#代码中根据num个数依次从内存中读取字符串,从内存中读取字符串函数为Marshal.PtrToStringAnsi(intPtr),需要注意的是如果C++传出的包含中文字符,那么在C#端可能显示乱码。
————————————————
版权声明:本文为CSDN博主「weixin_46846685」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_46846685/article/details/116402452

标签:C#,C++,char,互传,result,类型,TestDll
From: https://www.cnblogs.com/wuguoqiang/p/17588544.html

相关文章

  • How to disable Windows 10 DNS Cache services
    HiAdithya,DisableDNSClientthroughregistry:GotoHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Dnscache,LocatetheStartregistrykeyandchangeitsvaluefrom2(Automatic)to4(Disabled)DisableDNSclientthroughcommandline:REGadd......
  • C#动态调用C/C++的DLL
    C#调用C/C++的dll有两种方式,下边就写一下两种不同方式的调用方法。1.DllImport方式[DllImport("CalcDll")]publicexternintAdd(inta,intb);其中CalcDll为C++动态库,Add为动态库中的方法,使用DllImport引入需要加载的DLL,使用关键字extern修饰C++库中的方法,之后正常调用即可。......
  • Asp.Net Core 集成JWT采用Rsa非对称密钥并实现自定义身份验证
    授权和鉴权分为了两个项目。首先是授权:建立Asp.netcore项目,并在Nuget包安装System.IdentityModel.Tokens.Jwt新建一个WebApi用于登录,这里使用账户密码方便调试。另外BaseResult是我封装的一个统一返回数据类型。需要注意的是audience以及JwtRegisteredClaimNames.Name......
  • C#调用C/C++动态库dll异常:对 PInvoke 函数调用导致堆栈不对称问题
    C#调用C/C++动态库dll异常:对PInvoke函数调用导致堆栈不对称问题雨渡石桥已于2023-02-2112:04:29修改973收藏1文章标签:windowsc++c#版权结论:如果你是用C#调用C的动态库,如果出现“对PInvoke函数调用导致堆栈不对称问题”,建议优先调整CallingConvention的值,建议改为Ca......
  • PowerPoint 2019 for Mac(PPT2019) v16.76 beta中文版
    PowerPoint2019mac是一款幻灯片制作软件,是 office 2019套件中的一部分。它可以帮助用户创建各种类型的演示文稿,包括商务演讲、学术报告、培训材料等等。与之前版本相比,提供了更多的功能和改进,例如更强大的演示文稿制作工具、更好的视觉效果和更加智能的助手。PowerPoint2019......
  • ChatGPT狂飙240天,欢迎来到AIGC时代!
    2023年的互联网,针对GPT的讨论已经蔚然成风,相关话题热度如火箭一般蹿升。生成式预训练模型(GenerativePre-trainedTransformer,简称GPT)是人工智能AI子领域自然语言处理中的一个重要技术,由OpenAI团队开发。GPT是一种基于互联网的、可用数据来训练的、文本生成的深度学习模型,并在不同......
  • C# 字符串转码后操作二进制文件
    String转码后写入二进制文件,读二进制文件进行解码返回。publicclassBinaryClass{///<summary>///写二进制文件///</summary>///<paramname="binFile"></param>///<paramname="str">&......
  • 【C++学习之路】引用(reference)
    变量名实质上是一段连续内存空间的别名,是一个标号,程序通过变量来申请并命名内存空间。引用的本质:就是给变量名取一个别名普通变量的引用inta=10;//定义的时候,&修饰变量为引用b就是a的别名(引用)//洗头膏不会为引用开辟空间int&b=a;//引用必须初始化系统数组的引用intarr[5]......
  • CSS隐藏滚动条
    一、纯CSS+div样式隐藏在需要滚动的元素外面再套一个div,给最外面的div设置样式overflow:hidden,宽度比需要滚动的元素小;之后给需要滚动的元素设置样式overflow-x:hidden;overflow-y:scroll;<styletype="text/css">*{margin:0;padding:0;}.box{width:100px;height:300px;......
  • 【软件测试】简易挡板测试——Mock服务搭建及使用方法
    1. Mock介绍1.1Mock简介Mock测试也被称为替代测试与挡板测试,Mock 测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。这个虚拟的对象就是Mock对象。Mock对象就是真实对象在调试期间的代替品。形如上图,服务B就可以用Mo......