2012-05-10 3 views
2

Существует несколько способов сделать это, но примеры, которые я пробовал, не сработали для меня.PInvoke стиль передачи структуры с элементом динамический массив указателей

Я где-то читал, что использование небезопасных указателей будет способом перехода на более сложные структуры, требующие указателей. (Извините, но я не смог найти источник снова)

Моя последняя попытка выглядит примерно так:

unsafe public struct ComplexStruct { 
    public Int32 NumSubStruct; 
    public SubStruct*[] arr; 
} 

unsafe public static extern UInt32 DLL_Call(ref ComplexStruct p); 

function { 
unsafe { 
    ComplexStruct p = new ComplexStruct(); 
    p.NumSubStruct = 2; 
    p.arr= new SubStruct*[p.NumSubStruct]; 
    SubStruct p1 = new SubStruct(); 
    SubStruct p2 = new SubStruct(); 
    p.arr[0] = &p1; 
    p.arr[1] = &p2; 


    testLogHandlerHandle = DLL_Call(ref p); 
} 
} 

Я получаю ошибку, которая говорит, что SubStruct не может быть выстраивали (Подпись не Interop совместимый).

Возможно ли передать объект без маршалинга? (DLL должна быть загружена в том же пространстве процесса, что и приложение C#).

Если нет, то каким будет самый простой способ передать копию объекта?

Примечание: изменение DLL не является проблемой. Я смутно знаю некоторые другие решения, такие как C++/CLI, но у меня только относительно небольшое количество типов структуры, которые необходимо передать таким образом.

EDIT: Несколько заметок:

  1. массив должен с помощью динамического
  2. Фактические структур немного более сложные (есть 4 слоя вложенных структур, как это), так что я думаю, что добавление они будут отвлекать внимание от вопроса, но для полноты картины, вот как я бы объявить их в C++:

    struct ComplexStruct { 
    
        unsigned int NumSubStruct; 
    
        SubStruct** arr; 
    
    }; 
    
    struct SubStruct { 
    
        unsigned int NumSubStruct; 
    
        //some more datamembers here as well 
    
        SubSubStruct** arr; 
    
    }; 
    

(дополнительный окольные не надо, но я полагал, что это может быть полезно, чтобы иметь возможность объявить массив указателей SubStruct в IntPtrs)

+0

Можете ли вы показать декларацию C++ для двух структур? Лично я очень сомневаюсь, что «небезопасно» - это путь. –

+0

Эта дополнительная направленность может навредить вам. Без него было бы легче. –

ответ

0

Вы должны использовать что-то вроде this и this.

[StructLayout(LayoutKind.Sequential)] 
public struct ComplexStruct 
{ 
    public Int32 NumSubStruct; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_NO_SUB_STRUCTS)] 
    public SubStruct[] arr; 
} 

public static extern UInt32 DLL_Call(IntPtr p); 

Тогда маршал его с чем-то вроде этого:

IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ComplexStruct))); 

try 
{ 
    // Copy the struct to unmanaged memory. 
    Marshal.StructureToPtr(p, ptr, false); 

    testLogHandlerHandle = DLL_Call(ptr); 
} 
finally 
{ 
    // Free the unmanaged memory. 
    Marshal.FreeHGlobal(pnt); 
} 

Постарайтесь избавиться от всего опасного материала, я сомневаюсь, что его надо!

+0

Я предполагаю, что использование произвольно большого числа для SizeConst было бы очень плохо для производительности. Идеи для этого динамически? – 00500005

+0

Должно быть достаточно легко сделать динамически. –

+0

Не знаю, работает ли это, но SizeConst, вероятно, только для Marshal.SizeOf(). Если вы сами вычисляете размер, то это можно сделать динамически. Худший случай StructureToPtr не будет работать, и вам придется копировать каждую SubStructure самостоятельно. – DavWEB

1

Как это может быть?

unsafe public struct ComplexStruct 
{ 
    public Int32 NumSubStruct; 
    public SubStruct** arr; 
} 

unsafe static void Main(string[] args) 
{ 
    ComplexStruct p = new ComplexStruct(); 
    p.NumSubStruct = 2; 
    SubStruct[] s = new SubStruct[p.NumSubStruct]; 
    // no need to new here, valuetype array 
    s[0].value = 1; 
    s[1].value = 2; 
    fixed (SubStruct* sp = s) 
    fixed (SubStruct** spp = new SubStruct*[] { sp }) 
    { 
    p.arr = spp; 
    testLogHandlerHandle = DLL_Call(ref p); 
    } 
} 
+0

Оба выше и фиксированные (SubStruct * sp1 = & s [0]) фиксированные (SubStruct * sp2 = & с [1]) фиксированной (SubStruct ** SPP = новый SubStruct * [] {sp1, sp2}) дают меня нарушает доступ к памяти. DLL получает выполнение, и данные, как представляется, проходят правильно (хотя бы со второй версией). – 00500005

Смежные вопросы