C#项目要采用第三方的方案实现某个功能,第三方提供了一个C++实现的库Dll库。然鹅,在实现的过程中遇到一系列的问题,最后都搞懂了,现分享下过程,主要问题总结如下:
1、System.DllNotFoundException 解决之路无法加载DLL“xxx.dll”:找不到指定的模块(异常来自HRESULT:0X8007007E)
2、未处理System.BadImageFormatException,试图加载格式不正确的程序。 (异常来自 HRESULT:0x8007000B)
3、System.EntryPointNotFoundException:Unable to find an entry point named
4、C# 和C++ 数据结构映射(结构体指针)
① 右键添加引用报如下错误:请确保此文件可访问并且是一个有效的程序集或COM组件
② 按网上说的 regsvr32 dll 还是不通
③ 既然此法不通换个思路,得用DllImport代码导入方式
DllImport代码举例如下(注意int* 用IntPtr ,char* 用string替换)
[DllImport("xxxxxxxx.dll"]public static extern IntPtr XXXXOpen(string xxxx01, string xxxx02){……};
④ 然鹅,又报错误 无法加载 DLL“xxxx.dll”: 找不到指定的模块
继续度娘,发现有可能是缺少依赖项的情况。下载使用depends.exe查看xxxx.dll的依赖项,分析看,果不其然缺了不少依赖库啊,下载缺失的依赖项到Debug目录下,解决
⑤然鹅,又报错误 System.BadImageFormatException
这个是因为,程序中引用外部dll文件的目标平台的版本x86和x64不一致引起的
⑤然鹅,又报错误 System.EntryPointNotFoundException
原因:在C++函数声明时要将 extern “C” 添加在 DLL 函数声明之前 。
如果不加的话,C++编译为dll之后,函数名会发生变化,会多了一些符如号?@@等,有些参数顺序还会发生变化。可以用DllAnalyzer工具查看dll的输出函数名,发现输出的函数名有所变化,多了@xxx和一些别的奇怪的字符,实际上是因为C++重载机制造成的,使用使用extern "C"关键字即可或者直接把那一长串拷贝过去可以解决!
[DllImport("a.dll",EntryPoint="?F@@YAHXZ")]
public extern static int F();
⑥ 至于C# 和C++ 数据结构映射(结构体指针),参考如下
PS:后面找到有个工具可以自己生成 ===>【CLRInsideOut】C#调用C++DLL结构体或函数声明代码生成工具
struct A{double a[20];
};struct B{double b[20];int c[10];
}; extern “C” _declspec(dllexport) int abc(char* filePath, A* input, B* output,int flag
);
[StructLayout(LayoutKind.Sequential)]
public struct A
{[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20, ArraySubType = UnmanagedType.R8)]public double[] a;
}[StructLayout(LayoutKind.Sequential)]
public struct B
{[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20, ArraySubType = UnmanagedType.R8)]public double[] b;[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20, ArraySubType = UnmanagedType.I4)]public int[] c;
}[DllImport("xxx.dll", EntryPoint = "abc", CallingConvention = CallingConvention.Cdecl)]
public static extern int abc(string filePath, ref A input, out B output,int flag );
如上就是我遇到的坑及解决方法,希望给有需要的同学有所帮助!!!