我正在开发一个VS 2015 MVC C#Web应用程序,它加载了我没有源代码的第三方C ++ DLL。 DLL需要输入参数。新规范需要几个阵列成员。一个是int
数组,另一个是char
数组。
My C#struct将目标char
数组定义为byte
以匹配8位C ++ char:
[StructLayout(LayoutKind.Sequential)]
public unsafe struct MyDLLInput
{
public fixed int SomeList[288];
public fixed byte PathToData[256];
};
这个结构对我来说似乎是正确的,但现在我需要设定价值并且我没有取得任何成功。
MyDLLInput dllInput = new MyDLLInput()
{
SomeList = new int[] {0,12,33,67,93},
PathToData = "C:\\some\\path\\to\\data"
}
// Call 3rd Party DLL
MyDLLOutput = MyDLL.EntryPoint(MyDLLInput);
对于两个成员数组,我收到以下错误:
固定大小的缓冲区只能通过本地或字段访问。
这里至少有几件事情 - 除了使用本地设置值的正确方法之外,我还必须进行从string
到byte[]
的编码转换。
有人能为我提供一个设置这些值的简洁方法的代码示例吗?
答案 0 :(得分:3)
你有什么理由使用不安全的结构吗?你不能使用编组属性吗?见https://msdn.microsoft.com/en-us/library/eshywdt7(v=vs.110).aspx
无论如何,您需要知道如何从C#字符串转换为字节数组,这取决于您的C ++ DLL期望该字符串所在的编码。例如,在Windows上,它通常是" ANSI代码页",但在Linux / Unix上它可能是"当前的语言环境"或明确地" UTF-8"。
因此,一个让您最能控制编码的选项就是做一些像:
[StructLayout(LayoutKind.Sequential)]
public struct MyDllInput
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 288)]
public int[] SomeList;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] PathToData;
}
public static void Main()
{
MyDllInput dllInput = new MyDllInput()
{
SomeList = new int[288],
PathToData = new byte[256]
};
var listData = new int[] { 0, 12, 33, 67, 93 };
Array.Copy(listData, dllInput.SomeList, listData.Length);
var pathToDataBytes = Encoding.UTF8.GetBytes("C:\\some\\path\\to\\data");
Array.Copy(pathToDataBytes, dllInput.PathToData, pathToDataBytes.Length);
}
或者,您可以尝试将PathToData声明为字符串,然后使用编组属性让C#为您转换,而不是直接进行编码转换;见https://msdn.microsoft.com/en-us/library/s9ts558h(v=vs.110).aspx:
[StructLayout(LayoutKind.Sequential)]
public struct MyDllInput
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 288)]
public int[] SomeList;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =256)]
public String PathToData;
}
public static void Main()
{
MyDllInput dllInput = new MyDllInput()
{
SomeList = new int[288],
PathToData = "C:\\some\\path\\to\\data"
};
var listData = new int[] { 0, 12, 33, 67, 93 };
Array.Copy(listData, dllInput.SomeList, listData.Length);
}
在第二种情况下,当您声明EntryPoint时,在DllImportAttribute上设置CharSet属性以使字符串转换按您希望的方式发生,这一点非常重要。在你的情况下,你可能想要CharSet.Ansi,因为你的DLL采用char *而不是wchar_t *。例如,
[DllImport("MyDll.dll", CharSet = CharSet.Ansi)]
private static extern void EntryPoint(ref MyDllInput input);