Как упорядочить массив структур в C #? - PullRequest
2 голосов
/ 02 декабря 2010

Я должен вызвать C ++ DLL в C #.И заголовок dll выглядит следующим образом (упрощенно):

// Заголовок 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);
    }
};

// эта функция используется для вывода всех значений переменных экземпляра структуры

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

И я определил следующий класс в C #

// 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);
}

И вывод будет следующим:

unmanaged_structсводка:

0

1.12104e-044

Необработанное исключение: System.AccessViolationException: Попытка чтения или записи в защищенную память.Это часто указывает на то, что другая память повреждена.в callunmanageddll.UnmanagedDllCallTest.unmanagedstruct_summary (UnmanagedStr uct [] usList, длина Int32) в callunmanageddll.Program.Main (аргументы String []) в c: \ users \ dynaturtle \ documentme nts \ visual studio 2010 \ Projects \ callunmanageddll \ callunman.cs: ​​lin e 68

C ++ dll в порядке, так как я написал тест на C ++, и функция работает хорошо.Я прочитал эту ветку , но, похоже, решение не сработало в моем случае.Какие-либо предложения?Заранее спасибо!

Ответы [ 3 ]

5 голосов
/ 02 декабря 2010

Используйте Marshal.PtrToStructure. Здесь есть образец здесь .

Таким образом, вам придется изменить сигнатуру метода с массива out структуры на out IntPtr. Однако вам нужно знать размер буфера, который передается.

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
    }

}
1 голос
/ 02 декабря 2010

Во-первых: Vector и UnmanagedStruct должны быть структурами, а не классами.

0 голосов
/ 19 апреля 2013

JIC Я бы поделился своим подходом. Возможно, это не ожидаемый ответ, когда я трачу время на решение своей проблемы.

У меня есть следующая структура для предоставления некоторых данных из 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

Чтобы принять эти данные из C ++, я могу сделать это

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

Чтобы сделать то же самое на 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;
}

Как я уже видел, существуют разные подходы к этому. Это одна из них. И это работает для меня. Возможно, этот пост не решит проблему, но будет хорошей отправной точкой для начала

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...