C#程序调用C++动态库(dll文件)遇到的坑及解决
作者:CC_21H
C#程序调用C++程序DLL遇到的坑
这两天有一个需求就是C++写的程序,给外包公司写界面,他们用的是C#写的,所以我得生成C++动态库(dll文件)给他们调用,过程中遇到了很多坑
这里记录下来给大家参考。
C#调用c++动态库(dll)方法
总结一下就是先建一个C++程序,建立的时候选择dll类型。(或者右击项目-属性-常规-配置类型里将exe类型修改为dll类型)
然后建立一个头文件(test.h),一个c++文件(test.cpp)
test.h文件声明一个函数
extern "C" __declspec(dllexport) int add(int a, int b);
test.cpp文件写函数体,并导入test.h头文件
#include"test.h" extern "C" __declspec(dllexport) int add(int a, int b){ return a+b; };
然后右击项目,点击重新生成
并记录下生成dll的路径
然后创建一个c#程序用DllImport语句导入,路径是前面dll的路径
using System; using System.Runtime.InteropServices; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication2 { class Program { //这里注意,一个函数导入一次,如果是两个函数就导入两次,路径是前面生成的dll路径 [DllImport(@"D:\CC\Project7_源码版本_dll\Project7\Project7.dll", EntryPoint = "add")] extern static int add(int a,int b); static void Main(string[] args) { Console.WriteLine(add(2,3)); Console.ReadKey(); } } }
然后在main函数里进行测试,运行即可
当然,如果真有这么简单也没必要发这篇博客了,你可能会遇到各种各样的坑,让你绝望,下面列举我遇到过的坑。
问题1:报错System.DllNotFoundException
这个问题首先要检查生成的dll和C#运行的环境位数是不是一致的,要么都是32位,要么都是64位。
如果位数没问题,那就一定是你把dll移动到其他地方去了,dll在哪生成的就在哪放在,不要乱移动啊!!!
在Debug目录下生成就Debug目录,在Release目录下生成就Release。DllImport写对应的路径就行了。
如果还是不行,建议看看其他的博客……反正博主这个问题没困扰多久就解决了
问题2:报错System.BadImageFormatException
这个,是我苦恼了两天的报错,一直没办法解决。最后没办法找了我室友c++大神帮忙解决了,就是下面这个一流软件架构师。
主要问题还是位数的问题,程序调用了位数不一致的库。
解决方案1:
生成和调试都用32位的。
解决方案2:
如果你就是想用64位的,那就右击C#程序-属性-生成-目标平台改为x64(或者Any CPU,取消勾选首选32位)
就是这个问题,你觉得自己明明选择了x64运行,可它其实还是默认32位运行的。
如果只要调用加法的测试函数,基本上就只会碰到上面两个问题。如果你想调用自己的程序,你可能会遇到下面这些问题
问题3:参数有字符串,报错System.AccessViolationException
废话不多说,直接上解决方案:
cpp文件参数类型写char*,在函数体里面可以直接把char* 类型赋值给string类型,但是参数必须是char*类型
extern "C" __declspec(dllexport) int add(char* str);
c#程序参数写string
[DllImport(@"D:\\test.dll", EntryPoint = "add")] extern static int add(string str);
还有一种可能会报错System.AccessViolationException,就是函数不对应,我有次是 EntryPoint = "add"这个忘记改成对应的函数名了,也是报的这个错,所以仔细检查,把函数名对应起来。
问题4:如何返回多个值
好像有种方法是返回结构体,但我尝试了一下没成功就用了另一种办法,一下就成功了。
那就是,传地址:
cpp文件参数类型写地址int*
extern "C" __declspec(dllexport) int add(int* a,int* b){ a++; b++; return a; };
c#程序参数写ref int
[DllImport(@"D:\\test.dll", EntryPoint = "add")] extern static int add(ref int a,ref int b); static void Main(string[] args) { //这里必须先初始化 int a=0; int b=0; Console.WriteLine(add(ref a,ref b)); Console.WriteLine(a); Console.WriteLine(b); Console.ReadKey(); }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。