Я пытаюсь создать обертку в C dll, и я пытаюсь вызвать функцию, которая принимает функцию обратного вызова, получает объект как указатель, который передается обратно.Как мне вызвать функцию в C++ Dll из C#, которая имеет void * callback и параметр объекта
заголовочных файл delares
extern int SetErrorHandler(void (*handler) (int, const char*, void*),
void *data_ptr);
Обработчик является функцией обратного вызова, которая вызывается, когда происходит ошибка и data_ptr любой предмет (состояние), которое передается обратно к вам, в случае моего приложение, которое будет именно этим (текущий объект).
Я могу вызвать функции в dll, которая использует marshalled константные типы, такие как простые типы строк, ints и т. Д. Но я не могу понять, как просто маршировать указатель на объект C#, являющийся состоянием.
Чтобы передать объектную ссылку на функцию C из того, что я нашел, выполнив поиск здесь, и в противном случае кажется, что мне нужен тип структуры, чтобы иметь возможность маршаллировать функцию, поэтому я создал структуру для хранения объекта :
[StructLayout(LayoutKind.Sequential)]
struct MyObjectState
{
public object state;
}
EDIT: Я пытался поставить атрибут: [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
я получаю сообщение об ошибке:
The structure must not be a value class.
Я сделал много поиска здесь и нашел различные вещи на Маршалле и пустоте *, но ничто не помогло мне заставить это работать
Спасибо.
В этом случае это правда. Действительно, мне действительно не нужно передавать это данные, поскольку он будет доступен в моем обратном вызове объекта, но я хотел бы предоставить правильный вызов функции, когда пользователь хочет обеспечить контекст. Я думаю, управление данными может обрабатываться объектом C# для поддержания состояния/контекста. Поэтому я предполагаю, что это решает мою проблему, но я предполагаю, что исходный вопрос о том, как или можно передать объект, остается без ответа. – Andre
Вы действительно не хотите передавать ссылку на объект C# на мой взгляд. Помните, что управляемые объекты могут быть перемещены GC. Собираетесь ли вы закрепить такие объекты? И что может сделать нативный код с такой штукой? Это абсолютно непрозрачно. Вы можете использовать 'ObjectIDGenerator' для получения уникального идентификатора для каждого объекта, но лично я думаю, что ваш вопрос лучше всего решать, пошагово его! –
То, что вы говорите, имеет смысл, и я думаю, что ответ - это не делать этого/избегать, это может быть не невозможно, но вы не должны, спасибо – Andre