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

 更新时间:2023年08月14日 11:03:37   作者:CC_21H  
这篇文章主要介绍了C#程序调用C++动态库(dll文件)遇到的坑及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

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

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

这里记录下来给大家参考。

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();
        }

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

最新评论