Опитвам се да създам обвивка на C dll и се опитвам да извикам функция, която има функция за обратно извикване, получава обект като указател, който се предава обратно.
Файлът .h работи
extern int SetErrorHandler(void (*handler) (int, const char*, void*),
void *data_ptr);
Манипулаторът е функция за обратно извикване, която се извиква, когато възникне грешка и data_ptr е всеки обект (състояние), който се предава обратно към вас, в случая на моето приложение, което ще бъде просто това (текущ обект).
Мога да извикам функции в dll, който използва маршалирани константни типове като прости типове низове, int и т.н. Но не мога да разбера как просто да маршалирам указател към C# обект, който е състоянието.
За да предам препратката към обекта към функцията C от това, което намерих, като търся тук, и в противен случай изглежда, че имам нужда от структурен тип, за да мога да маршалирам към функцията, така че създадох структура, която да задържа моя обект:
[StructLayout(LayoutKind.Sequential)]
struct MyObjectState
{
public object state;
}
РЕДАКТИРАНЕ: Опитах се да поставя атрибут: [MarshalAs(UnmanagedType.Struct, SizeConst = 4)]
в свойството public object state
, но това води до същата грешка, така че го премахнах, така или иначе не изглежда да работи.
Структурата съдържа едно свойство на обект за задържане на всеки обект за функцията за обратно извикване.
Декларирах делегата в C#, както следва:
delegate void ErrorHandler(int errorCode, IntPtr name, IntPtr data);
След това декларирах функцията за импортиране в C#, както следва:
[DllImport("somedll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int SetErrorHandler handler, IntPtr data);
След това създадох функция за обратно извикване в моя C# код:
void MyErrorHandler(int errorCode, IntPtr name, IntPtr data)
{
var strName = Marshal.PtrToStringAnsi(name);
var state = new MyObjectState();
Marshal.PtrToStructure(data, state);
Console.WriteLine(strName);
}
Мога да извикам библиотечната функция, както следва:
var state = new MyObjectState()
{
state = this
};
IntPtr pStruct = Marshal.AllocHGlobal(Marshal.SizeOf(state));
Marshal.StructureToPtr(state, pStruct, true);
int ret = SetErrorHandler(MyErrorHandler, pStruct);
Обаждането работи и функцията за обратно извикване се извиква, но не мога да осъществя достъп до данните във функцията за обратно извикване и когато опитам Marshal.PtrToStructure
получавам грешка:
Структурата не трябва да бъде стойностен клас.
Търсих много тук и намерих различни неща за Marshall и void*, но нищо не ми помогна да накарам това да работи
Благодаря.