У меня есть неуправляемый 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 = тест ();
При объявлении управляемой функции вам необходимо сопоставить типы указателей со ссылочными значениями или значениями 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
}
}