简体   繁体   English

如何在C#中封送结构数组?

[英]How to marshal an array of structure In C#?

I have to call a C++ dll in C#. 我必须在C#中调用C ++ dll。 And the header of the dll is as following(simplified): dll的头文件如下(简化):

//Header of C++ // C ++的标题

struct vector
{
    float x;
    float y;

    vector()
    {}

    vector(float x0, float y0)
    {
        x = x0;
        y = y0;
    }
};

struct unmanaged_struct
{
    int int_var;
    float float_var;
    char* chars_var;
    vector vector_var;

    unmanaged_struct(int i, float f, char* ch, float vec_x, float vec_y) 
    {
        int_var = i;
        float_var = f;
        chars_var = ch;
        vector_var = vector(vec_x, vec_y);
    }
};

// this function is used to output all the variable values of the struct instance //此函数用于输出struct实例的所有变量值

extern "C" __declspec( dllexport )  void unmanagedstruct_summary(unmanaged_struct* us_list, int length);

And I defined following class in C# 我在C#中定义了以下类

//CSharp // CSHARP

[StructLayout(LayoutKind.Sequential)]
public class Vector
{
    public float x;
    public float y;

    public Vector(float f1, float f2)
    {
        x = f1;
        y = f2;
    }
}

[StructLayout(LayoutKind.Sequential)]
public class UnmanagedStruct 
{ 
    public int int_var;
    public float float_var;
    public string char_var;
    public Vector vector_var;

    public UnmanagedStruct(int i, float f, string s, Vector vec)
    {
        this.int_var = i;
        this.float_var = f;
        this.char_var = s;
        this.vector_var = vec;
    }
}

class UnmanagedDllCallTest
{
    [DllImport("unmanageddll.dll", EntryPoint = "unmanagedstruct_summary")]
    public  static extern void unmanagedstruct_summary([Out]UnmanagedStruct[] usList, int length);    

  static void Main(string[] args)
    {

        UnmanagedStruct[] usList = new UnmanagedStruct[1];
        usList[0] = new UnmanagedStruct(1, 1.0f, "aa", new Vector(10, 1));       
        usList[1] = new UnmanagedStruct(2, 2.0f, "ba", new Vector(20, 2));  
        UnmanagedDllCallTest.unmanagedstruct_summary(usList, 2);
}

And the output is as following: 输出如下:

unmanaged_struct summary: unmanaged_struct摘要:

0 0

1.12104e-044 1.12104e-044

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. 未处理的异常:System.AccessViolationException:尝试读取或写入受保护的内存。 This is often an indication that other memory is corrupt. 这通常表明其他内存已损坏。 at callunmanageddll.UnmanagedDllCallTest.unmanagedstruct_summary(UnmanagedStr uct[] usList, Int32 length) at callunmanageddll.Program.Main(String[] args) in c:\\users\\dynaturtle\\docume nts\\visual studio 2010\\Projects\\callunmanageddll\\callunmanageddll\\Program.cs:lin e 68 在c:\\ users \\ dynaturtle \\ docnt nts \\ visual studio 2010 \\ Projects \\ callunmanageddll \\ callunmanageddll \\ Program中的callunmanageddll.Program.Main(String [] args)中的callunmanageddll.UnmanagedDllCallTest.unmanagedstruct_summary(UnmanagedStr uct [] usList,Int32长度) .cs:lin e 68

The C++ dll is OK as I have written test in C++ and the function works well. C ++ dll正常,因为我已经用C ++编写了测试,并且该功能运行良好。 I have read this thread but it seems the solution didn't work in my case. 我已经阅读了该线程,但是看来该解决方案在我的情况下不起作用。 Any suggestions? 有什么建议么? Thanks in advance! 提前致谢!

Use Marshal.PtrToStructure . 使用Marshal.PtrToStructure There is a sample here . 有一个样品在这里

So you would have to change the signature of the method from out structure array to out IntPtr. 因此,您必须将方法的签名从out结构数组更改为out IntPtr。 However, you need to know the size of the buffer being passed out. 但是,您需要知道要传递的缓冲区的大小。

public struct Vector
{
    public float x;
    public float y;

}

public struct UnmanagedStruct 
{ 
    public int int_var;
    public float float_var;
    public string char_var;
    public Vector vector_var;

}

class UnmanagedDllCallTest
{
    [DllImport("unmanageddll.dll", EntryPoint = "unmanagedstruct_summary")]
    public static extern void unmanagedstruct_summary([Out] IntPtr ptr, int length);    

  static void Main(string[] args)
  {

    for(int i=0; i<length; i++)
    {
        UnmanagedStruc st;
        Marshal.PtrToStructure(ptr, st);
        // increment ptr and move forward
    }

}

第一:Vector和UnmanagedStruct应该是结构,而不是类。

JIC I'd share my approach. JIC我会分享我的方法。 Perhaps this is not an expected answer by at one time I spend a time to resolve my issue. 也许这不是我一次花时间来解决问题的预期答案。

I have the following structure to expose some data from DLL. 我具有以下结构来公开DLL中的某些数据。

//C++ code
    struct State
    {
        const wchar_t * name;
        unsigned int state; 
    };

APIENTRY bool get_states(H_PRCSR, MacroState *, const int sz); //pay attention, function accepts already allocated array and size for it

To accept this data From C++ I can do this way 从C ++接受此数据,我可以这样做

std::vector<State> states(desired_size);
get_states(hparser, &states[0], states.size());

To do the same on C# I used the following way 为了在C#上执行相同的操作,我使用了以下方法

//C#
[StructLayout(LayoutKind.Sequential)]
public struct Status
{
   public IntPtr name;
   public uint state;

   public string getName()
   {
     if (name == IntPtr.Zero) return "<no-value>";
     return Marshal.PtrToStringUni(name);
   }
}

//And import function...

[DllImport(dll, CallingConvention = CallingConvention.Winapi)]
private static extern bool get_states(IntPtr p, [Out]MacroFlag[] flags, int flags_size);

//And simple decoder
public static Status[] getAll(IntPtr p, int size)
{
   var results = new Status[size];

   get_states(p, results, size);

   return results;
}

As, I saw the are different approaches to do this. 因此,我看到了执行此操作的不同方法。 This is one of them. 这就是其中之一。 And it works for me. 它对我有用。 Perhaps, this post will not resolve the issue but will be a good point to start 也许,这篇文章无法解决问题,但将是一个不错的起点

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM