• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

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

武飞扬头像
陆沙
帮助1

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合在一起,导致代码大段飘红。。。注释掉就好了。
这是我的问题=。=

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfkbaj
系列文章
更多 icon
同类精品
更多 icon
继续加载