c# - C# 中的 C++ 结构

标签 c# c++ struct pinvoke dllimport

我通过 DllImport 在我的 C# 项目中使用用 C++ 编写的 DLL,我正在使用的函数之一如下所示:

    [DllImport("dds.dll", CharSet = CharSet.Auto)]
    private static extern int Par(
        ddTableResults2 tableResult,
        ref parResults ParResult,
        int vul
    );

parResults 结构在 C++ 中的定义如下:

struct parResults {
  /* index = 0 is NS view and index = 1 
     is EW view. By 'view' is here meant 
     which side that starts the bidding. */
  char          parScore[2][16];
  char          parContractsString[2][128]; 
};

C++函数的开始

int STDCALL Par(struct ddTableResults * tablep, struct parResults *presp, 
    int vulnerable)

我应该如何在 C# 中定义上述结构,以便能够将该结构作为 en 引用发送到 DLL 函数中?

这是我尝试过的但根本不起作用,我只是遇到访问冲突错误

    [StructLayout(LayoutKind.Sequential)]
    public struct parResults
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public char[,] parScore;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
        public char[,] parContractsString;

        public parResults(int x)
        {
            parScore = new char[2,16];
            parContractsString = new char[2,128];
        }
    }

最佳答案

在 C# 中编码这是一个非常棘手的结构。有多种尝试方法,但我认为将字符数组表示为字节数组并手动编码字符串是最干净的方法。这是我的意思的演示:

C++

#include <cstring>

struct parResults {
    char          parScore[2][16];
    char          parContractsString[2][128];
};

extern "C"
{
    __declspec(dllexport) void foo(struct parResults *res)
    {
        strcpy(res->parScore[0], res->parContractsString[0]);
        strcpy(res->parScore[1], res->parContractsString[1]);
    }
}

C#

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        [StructLayout(LayoutKind.Sequential)]
        class parResults 
        {
            private const int parScoreCount = 2;
            private const int parScoreLen = 16;
            private const int parContractsStringCount = 2;
            private const int parContractsStringLen = 128;

            [MarshalAs(UnmanagedType.ByValArray, 
                SizeConst = parScoreCount * parScoreLen)]
            private byte[] parScoreBuff;

            [MarshalAs(UnmanagedType.ByValArray, 
                SizeConst = parContractsStringCount * parContractsStringLen)]
            private byte[] parContractsStringBuff;

            public string getParScore(int index)
            {
                string str = Encoding.Default.GetString(parScoreBuff, 
                    index * parScoreLen, parScoreLen);
                int len = str.IndexOf('\0');
                if (len != -1)
                    str = str.Substring(0, len);
                return str;
            }

            public void setParScore(int index, string value)
            {
                byte[] bytes = Encoding.Default.GetBytes(value);
                int len = Math.Min(bytes.Length, parScoreLen);
                Array.Copy(bytes, 0, parScoreBuff, index * parScoreLen, len);
                Array.Clear(parScoreBuff, index * parScoreLen + len,
                    parScoreLen - len);
            }

            public string parContractsString(int index)
            {
                string str = Encoding.Default.GetString(parContractsStringBuff,
                    index * parContractsStringLen, parContractsStringLen);
                int len = str.IndexOf('\0');
                if (len != -1)
                    str = str.Substring(0, len);
                return str;
            }

            public void setParContractsString(int index, string value)
            {
                byte[] bytes = Encoding.Default.GetBytes(value);
                int len = Math.Min(bytes.Length, parContractsStringLen);
                Array.Copy(bytes, 0, parContractsStringBuff,
                    index * parContractsStringLen, len);
                Array.Clear(parContractsStringBuff, 
                    index * parContractsStringLen + len,
                    parContractsStringLen - len);
            }

            public parResults()
            {
                parScoreBuff = new byte[parScoreCount * parScoreLen];
                parContractsStringBuff = 
                    new byte[parContractsStringCount * parContractsStringLen];
            }
        };

        [DllImport(@"...", CallingConvention = CallingConvention.Cdecl)]
        static extern void foo([In,Out] parResults res);

        static void Main(string[] args)
        {
            parResults res = new parResults();
            res.setParContractsString(0, "foo");
            res.setParContractsString(1, "bar");
            foo(res);
            Console.WriteLine(res.getParScore(0));
            Console.WriteLine(res.getParScore(1));
            Console.ReadLine();
        }
    }
}

这里我使用类来表示结构。由于 C# 中的类是引用,因此我们不使用 ref 声明该类型的参数。为了方便起见,我还使用了 __cdecl 来避免计算函数的修饰名称。但是您的库使用了 __stdcall,因此您需要坚持这一点。

该类(class)演示了双向发送数据。如果数据流受到更多限制,您可能可以简化代码。

关于c# - C# 中的 C++ 结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26510206/

相关文章:

c++ - HWND动态数组中的相同ID

结构 vector 的 C++ 初始化

c# - 定义精确大小的内存结构

c# - 如何使用 C# 从 .asc 文件中的特定位置读取数据

c++ - 是否建议让所有类都继承自 C++ 中的基类?

c# - 如何使用 Azure.Data.Tables 为 azure 表创建批量更新插入

c++ - 可轻松复制的需求和虚拟功能

c# - 如何从C#读取C程序生成的数据文件?

c# - 在 Visual Studio 中格式化文档以插入大括号?

c# - 从给定日期计算月份的星期几?