小言_互联网的博客

C#程序调用C++动态库(dll文件)遇到的坑

1142人阅读  评论(0)

C#程序调用C++程序DLL遇到的坑

这两天有一个需求就是C++写的程序,给外包公司写界面,他们用的是C#写的,所以我得生成C++动态库(dll文件)给他们调用,过程中遇到了很多坑,这里记录下来给大家参考。

C#调用c++动态库(dll)方法

可以参考

博客1
博客2

总结一下就是先建一个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();
        }

转载:https://blog.csdn.net/qq_41967982/article/details/114450427
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场