C#:如何设置不安全结构的成员阵列

C#: How to set member arrays of an unsafe struct

本文关键字:结构 不安全 成员 阵列 设置 何设置      更新时间:2023-10-16

我正在使用加载第三方C DLL的VS 2015 MVC C#Web应用程序,我没有源代码。DLL需要一个输入参数。新规格需要几个数组成员。一个是int数组,另一个是char数组。

我的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[]

有人可以为我提供一个安装这些值的干净方法的代码示例吗?

是否有某种原因使用不安全的结构?您不能使用编组属性吗?请参阅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#c#convent for you;请参阅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);
    }

在第二种情况下,重要的是,当您声明入口点时,请在dllimportattribute上设置charset属性,以使字符串转换按照所需的方式进行。在您的情况下,您可能想要charset.ansi,因为您的dll拿一个char*而不是wchar_t*。例如,

    [DllImport("MyDll.dll", CharSet = CharSet.Ansi)]
    private static extern void EntryPoint(ref MyDllInput input);