C#通过dll调用带参数的C++代码:传递字符串、返回int和int数组

2023/1/31 更新:传递int数组


以下是原文

工作上用到一个包,是c++写的,想在c#项目里调用,折腾了好久才终于成功了。踩坑踩了一天,我也是有毒。

环境:win10 + vs2022 + NETFramework4.7.2

制作dll

创建新项目-动态链接库
在这里插入图片描述
主要修改以下两个文件:pch.h和pch.cpp
在这里插入图片描述

修改pch.cpp

// pch.cpp: 与预编译标头对应的源文件
#include "pch.h"

//这里正常写c++代码,以下函数是我举例
char* getAlign(char* query, int queryLength, char* target, int targetLength) {...实现...}

// 要求返回一个int
int getStartsCount() {...实现...}

// 要求返回一个int[]
void getStartLocations(int* N, const int count) {
    for (int i = 0; i < count; i++) { ...对N[i]进行赋值... }
}

修改pch.h

只有extern那行是我写的,其他是自动生成的。

#ifndef PCH_H
#define PCH_H

// 添加要在此处预编译的标头
#include "framework.h"

extern "C" _declspec(dllexport) char* getAlign(char* query, int queryLength, char* target, int targetLength);
extern "C" _declspec(dllexport) int getStartsCount();
extern "C" _declspec(dllexport) void getStartLocations(int* N, const int count);

#endif //PCH_H

检查一下项目属性

在这里插入图片描述
ok了之后点击生成,输出中有下面这样的文字:

1>项目名.vcxproj -> C:\我的路径\项目名\x64\Debug\项目名.dll
========== “全部重新生成”: 1 成功,0 失败,0已跳过 ==========

c#中调用

检查项目属性

在这里插入图片描述
保持跟dll的一致。

调用

这里的路径当然可以改,因为我在调试,所以偷懒了。最终确定的dll应该加到c#的引用里去。

[DllImport("C:\我的路径\项目名\x64\Debug\项目名.dll")]
public static extern IntPtr getAlign(IntPtr query, int queryLength, IntPtr target, int targetLength);
[DllImport("C:\我的路径\项目名\x64\Debug\项目名.dll")]
public static extern int getStartsCount();
[DllImport("C:\我的路径\项目名\x64\Debug\项目名.dll")]
public static extern void getStartLocations([MarshalAs(UnmanagedType.LPArray, 
	SizeParamIndex = 1)] int[] Z, int count);
...
private void drawSeqCompCanvas() {
	string query = "hello";
	string target = "world";
	IntPtr p = getAlign(Marshal.StringToHGlobalAnsi(query), query.Length,
	Marshal.StringToHGlobalAnsi(target), target.Length);
	Console.WriteLine(Marshal.PtrToStringAnsi(p));

	int startCount = getStartsCount();
	int[] starts = new int[startCount];
	getStartLocations(starts, startCount);
	
}

解释一下:c++中的char*,c#是用IntPtr来接收的,所以无论是参数还是返回值,c++中的char*,在c#中都要改成IntPtr。至于Marshal那两句,就是IntPtr和String的互相转换。
对于int[],因为c++与c#不能传递数组,只能传递指针,所以需要指明长度。SizeParamIndex = 1表示index=1处是数组的长度,如果长度写在别的位置,需要修改。

常见bug

LINK : fatal error LNK1104: 无法打开文件“XXX.dll”

在制作dll时可能会出现这个问题。基本是因为另一个程序在引用这个dll,只要找到占用者,关掉即可。

System.AccessViolationException

c#调用dll出这个问题,很可能是调用dll里函数时,类型错误。比如C/C++中的unsigned short并不对应于C#中的ushort类型,而是UInt16这个类型,以及int[]传入C/C++,要用int* 接收。
我这次打包的问题则是,最开始时getAlign()接受的是string参数,但c++和c#的string似乎不一样,改成char*和IntPtr,问题解决。
参考:https://blog.csdn.net/Mr_L_K/article/details/112800806

重载min

copy代码时没注意,头文件里有下面这种,我直接copy过去了。

static inline int min(const int x, const int y) {
    return x < y ? x : y;
}

本来在单独头文件+限定namespace,是没有问题的,但是跟cpp合在一起,导致代码大段飘红。。。注释掉就好了。
这是我的问题=。=

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值