C#调用C 第三方DLL(无源)提出异常 - 不兼容PinVoke

C# calling C++ 3rd party DLL (no source) raises exception - not PInvoke Compatible

本文关键字:异常 PinVoke 不兼容 无源 调用 第三方 DLL      更新时间:2023-10-16

我正在使用vs 2015社区使用ASP.NET MVC Web应用程序,该应用程序使用第三方C DLL我没有源代码。文档非常稀缺,与第三方DLL的作者进行任何有用的沟通。

我问了一个相关的问题,并从@steven那里得到了一个很好的答案。我已经根据他的答案修改了我的代码,并试图成功打电话给第三方C DLL。代码:

//致电DLL

MyDLLInput _DLLInput = new MyDLLInput();
{
    SomeList = new int[288],
    ...
    SomeInt = 22,
    SomeDbl = 1.45,
    ...
    PathtoData = "C:\Some\Path\To\Data"
};    
var ids = new int[] { 0, 12, 33, 67, 93 };
Array.Copy(ids, _DLLInput.SomeList, ids.Length);
// Call DLL Entry Point
MyDLLOutput _DLLOutput = MyDLL.Unit(_DLLInput);

提高例外:

方法的类型签名不兼容。

//C#输入结构

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyDLLInput
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 288)]
    public int[] SomeList;
    ...
    public int SomeInt;
    public double SomeDbl;
    
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    public string PathtoData;
};

//C#输出结构

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyDLLOutput
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 288)]
    public int[] SomeList;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 288)]
    public double[] SomeDblArray;
    ...
    public int SomeInt;        // Same as input
    public double SomeDbl;     // Same as input
}

//C#dllimport

public class MyDLL
{
    [DllImport("My_DLL.dll",
        EntryPoint = "?Unit@@YA?AUDLLOutput@@UDLLInput@@@Z",
        CallingConvention = CallingConvention.Cdecl)]
    public static extern MyDLLOutput Unit(MyDLLInput UnitInput);
}

//C my_dll.h

#define  EPS_API __declspec(dllexport) 
struct DLLInput
{
    int SomeList[288];
    int SomeInt;
    double SomeDbl;
    char PathtoData[256];
};
struct DLLOutput
{
    int SomeList[288];
    double SomeDblArray[288];
    ...
    int SomeInt;
    double SomeDbl;
};
EPS_API DLLOutput Unit(DLLInput UnitInput);

我认为我一定要接近,但是找不到任何有帮助的结果或Google结果。有人看到我做错了什么吗?

扩大了本所说的话。

您需要将const定义删除到互操作结构外部。通过将结构的布局宣布为顺序,编译器的期望完全相同的成员数量完全相同的顺序,每种类型都声明,两侧的大小完全相同(即C 和C#)。这些const声明添加到内存布局中,因此签名不兼容。

char在C#和C 中的大小不一样,byte是(尽管它们可以根据平台更改,但两种类型至少可以保证至少8位)。您可以将byte数组而不是string marshall,但两者都很好。

创建与C char数组兼容的byte数组(相同大小)。

UTF8Encoding utf8 = new UTF8Encoding();
public byte[] PathToData = new byte[256];
PathToData = utf8.GetBytes(pathToDataString);

在另一个注意事项上,如果文档稀缺并且作者没有帮助,那么我个人会三思而后行。称其为一件事,调试是另一回事。