C#中的C ++结构 [英] C++ Struct in C#

查看:95
本文介绍了C#中的C ++结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过使用DllImport在我的C#项目中使用用C ++编写的DLL,而我正在使用的功能之一如下:

I'm using a DLL written in C++ in my C# project by using DllImport and one of the functions I'm using looks like this:

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

parResults结构是在C ++中定义的,如下所示:

The parResults struct is defined in C++ like this:

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#中定义上述结构,以便将该结构作为引用发送给DLL函数?

How should I define the above struct in C# to able to send that struct as en reference into the DLL function?

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

This is what I have tried but don't work at all and I just get a Access Violation Error

    [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#中封送的相当棘手的结构.尝试它的方法有很多种,但我认为将字符数组表示为字节数组并用手将其编组到字符串中将是最干净的方法.这是我的意思的证明:

This is quite a tricky struct to marshal in C#. There are various ways to attempt it, but I think that it will be cleanest to represent the character arrays as byte arrays and marshal to and from strings by hand. Here is a demonstration of what I mean:

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,因此您必须坚持使用.


Here I've used a class to represent the struct. Since a class in C# is a reference, we don't declare the parameters of that type with ref. I've also used __cdecl for convenience to avoid having to work out what the decorated name of the function would be. But your library used __stdcall and so you need to stick to that.

该类演示双向发送数据.如果数据流受到更多限制,则可以简化代码.

The class demonstrates sending data in both directions. You could probably simplify the code if the data flow was more restricted.

这篇关于C#中的C ++结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆