问题
I am using VS 2015 Community with an ASP.NET MVC Web Application that uses a 3rd party C++ DLL I do not have source code for. Documentation is very scarce as is any helpful communication with the authors of the 3rd party DLL.
I've asked a related SO Question and received a good answer from @Steven. I've modified my code according to his answer and am trying to make a successful call to the 3rd party C++ DLL. The code:
// Call 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);
Raises exception:
Method's type signature is not PInvoke compatible.
// C# Input STRUCT
[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# Output STRUCT
[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);
I think I must be close, but haven't been able to find any SO or Google results that help. Does anyone see what I'm doing wrong?
回答1:
Expanding on what Ben has said.
You need to remove the const definitions to outside the interopable struct. By declaring a layout of the struct as sequential the compiler is expecting EXACTLY the same number of members, declared in EXACTLY the same order, with each type declared, EXACTLY the same size on both sides (i.e in C++ and C#). Those const
declarations add to the memory layout and so the signatures are not compatible.
char
is not the same size in C# and C++, byte
is (although they can change depending on the platform, both types are guaranteed at least 8 bits). You could marshall a byte
array instead of a string
, but either is fine.
To Create a byte
array which is compatible with C++ char
array (same size).
UTF8Encoding utf8 = new UTF8Encoding();
public byte[] PathToData = new byte[256];
PathToData = utf8.GetBytes(pathToDataString);
On another note though, if documentation is scarce and the authors are not helpful, personally I would think twice about using this 3rd party. Calling it is one thing, debugging it is another.
来源:https://stackoverflow.com/questions/37902919/c-sharp-calling-c-3rd-party-dll-no-source-raises-exception-not-pinvoke-com