2016-03-18 14 views
1

Я хочу передать указатель на массив структуры из C# в C++. С помощью следующего кода я получаю только первый элемент в C++, второй и третий элементы массива не передаются. Зачем? Кроме того, попробовал использовать StructureToPtr, но не помог. Что я делаю неправильно?Передача указателя на массив структуры из C# в C++

C++ код

struct structure 
{ 
    short ps; 

}; 
    __declspec(dllexport)short Testmethod(structure** aa) 
    { 
    if (aa!= 0 && aa[0]->ps == 26 && aa[1]->ps == 27) 
    {   
     return 1; 
     }  
     return 0; 
    } 

C# код

[DllImport("Wrapper.dll", CallingConvention = CallingConvention.Cdecl)] 
public unsafe static extern short Testmethod(ref IntPtr a); 

    [StructLayout(LayoutKind.Sequential)]   
    public struct SampleStructure 
    { 
     public short ps; 

    }; 

SampleStructure[] data= new SampleStructure[3] { new SampleStructure { ps = 26 }, new SampleStructure { ps = 27 }, new SampleStructure { ps = 28 } }; 
         GCHandle gch = GCHandle.Alloc(data, GCHandleType.Pinned); 
         IntPtr ptr = gch.AddrOfPinnedObject(); 
         ret = Testmethod(ref ptr); 

Я не могу изменить C++ код, у меня нет доступа к нему. Если изменить код C++ как один из следующих способов, он работает. Как я могу это сделать без изменения кода на C++? Обновления:

Way 1: работает код, если я изменю C++. Но я не могу изменить код на C++. Это не мой код.

C++ код

__declspec(dllexport)short Testmethod(structure* aa) 

C# Код

  fixed (SampleStructure* pArray = dataInformation) 
      { 
       ret = Testmethod(pArray); 
      } 

Way 2: работает код, если я изменю C++. Но я не могу изменить код на C++. Это не мой код.

C++ код

__declspec(dllexport)short Testmethod(structure Getcsharpval[], int size) 

C# код

public unsafe static extern short Testmethod([MarshalAs(UnmanagedType.LPArray,SizeParamIndex=3)] SampleStructure[] array); 
SampleStructure[] data= new SampleStructure[3] { new SampleStructure { ps = 26 }, new SampleStructure { ps = 27 }, new SampleStructure { ps = 28 } }; 
ret = Testmethod(data); 
+0

У меня нет опыта работы с методами письма, подходящими для pinvoke, но попробовали ли вы изменить сигнатуру метода C++ на 'short Testmethod (structure * aa)'?Edit: Кроме того, поскольку вы передаете указатель, вы, вероятно, должны также передавать длину данных. – willaien

+0

Можете ли вы использовать C++/Cli в своем проекте? – alangab

ответ

0

Хорошо, я решил, создав указатель на указатели структур, используя следующий код.

[DllImport("Wrapper.dll", CallingConvention = CallingConvention.StdCall)] 
    public unsafe static extern short Testmethod (SampleStructure** passstructurepointer); 

    unsafe 
      { 
       fixed(SampleStructure** p2p = new SampleStructure*[3]) 
       { 
        for (short i = 0; i < 3; i++) 
        { 
         var a = stackalloc SampleStructure[1]; 
         a->ps = i; 
         p2p[i] = a; 
        } 
        var s= Testmethod(p2p); 
       } 
      } 
+0

Нет необходимости в небезопасных или stackalloc –

0

Я думаю, что ваша с функцией имеют неправильную прото. Try:

_declspec(dllexport)short Testmethod(structure* aa) 
{ 

    if (aa != 0 
     && aa[0].ps == 26 && aa[1].ps == 27) 

    { 
     return 1; 
    } 

    return 0; 
} 

В вашем C# образца у вас есть массив структуры. Массив является ссылочным типом, и вы исправляете необходимость прикрепить память. Массив представляет собой последовательность в памяти структуры, которая является типом значения (и не нуждается в выводе). Итак, в массиве у вас нет указателя, но прямо структура.

+0

Я не могу изменить код C++, у меня нет доступа к нему. Если сменить код C++, он работает. Как я могу это сделать без изменения кода на C++? Пожалуйста, обратитесь к обновленному вопросу –

0

Вам необходимо передать IntPtr[] в код C++.

[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)] 
static extern short Testmethod(IntPtr[] aa) 

Выделяют IntPtr[] массив и заполнить его. Сделайте это либо путем закрепления каждой структуры и использования адреса закрепленного объекта. Или сделайте это с помощью Marshal.StructureToPtr. Если вы используете последнее, вы должны освободить неуправляемую память после вызова.