Возврат указателей от неуправляемого до управляемого кода

У меня есть неуправляемый dll, который экспортирует следующую функцию:

SomeData* test();

Давайте примем SomeData как:

typedef struct _Data Data;  
struct _Data{  
    int a;  
    int b;  
}

Теперь я хочу вызвать эту функцию из кода C#. Я начинаю определять C# Struture, необходимый к пользовательскому маршалингу как это:

[StructLayout(LayoutKind.Sequential)]  
public class SomeData  
{  
    public Int32 a;  
    public Int32 b;  
}  

И теперь, я объявляю управляемую функцию:

[DllImport("DynamicLibrary.dll", CharSet=CharSet.Auto)]  
[return: MarshalAs(UnmanagedType.LPStruct)]  
public static extern SomeData test();  

И в основной функции я имею:

IntPtr ptr = test();  

Делая это, я получаю MarchalDirectiveException: "Не может упорядочить 'возвращаемое значение': Недопустимая управляемая/неуправляемая комбинация типа (Int/UInt должен быть соединен с SysInt или SysUInt)".

Я не выделил память для SomeData в C#, так как я ожидаю, что эта память выделяется в функции C, и их я использовал бы Маршала. Копия для передачи его управляемой памяти.

Какие-либо идеи?Спасибо

------------------------ОТРЕДАКТИРОВАННЫЙ ПОСЛЕ ОТВЕТА JaredPar--------------------

На самом деле я совершил ошибку при привыкании кода к моему вопросу. Реальная управляемая подпись, которую я использовал, была:

[DllImport ("DynamicLibrary.dll", CharSet=CharSet. Автоматический)]
[возврат: MarshalAs (UnmanagedType. LPStruct)]
общедоступный статический экстерн тест IntPtr ();

Ответ JaredPar все еще релевантен. Для получения правильного поведения у меня есть 2 варианта:

1) Используйте 'общедоступного статического экстерна тест IntPtr ()'; (без атрибута MarshalAs), подпись и затем получают доступ к возвращенному указателю как предложенный JaredPar.

2) Используйте 'общедоступного статического экстерна тест SomeData ()'; (с атрибутом MarshalAs), и затем просто используют SomeData sd = тест ();

7
задан Zé Carlos 26 February 2010 в 11:14
поделиться

1 ответ

При объявлении управляемой функции вам необходимо сопоставить типы указателей со ссылочными значениями или значениями IntPtr . В этом случае модификатор LPStruct не поможет. Самое простое решение - преобразовать возвращаемое значение test в IntPtr , а не в SomeData , поскольку собственный метод возвращает значение указателя. Затем вы можете написать следующую оболочку

[DllImport("DynamicLibrary.dll", CharSet=CharSet.Auto)]
public static extern IntPtr test();

public static SomeData testWrapper() {
  var ptr = test();
  try {
    return (SomeData)Marshal.PtrToStructure(ptr, typeof(SomeData));
  } finally {
    // Free the pointer here if it's allocated memory
  }
}
10
ответ дан 7 December 2019 в 01:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: