【发布时间】:2012-04-12 05:44:16
【问题描述】:
我正在尝试为 C dll 创建一个包装器,并且我正在尝试调用一个具有回调函数的函数,接收一个对象作为传回的指针。
.h 文件 delares
extern int SetErrorHandler(void (*handler) (int, const char*, void*),
void *data_ptr);
处理程序是一个回调函数,在发生错误时调用,data_ptr 是传回给您的任何对象(状态),在我的应用程序中就是 this(当前对象)。
我能够在使用编组常量类型(如简单类型字符串、整数等)的 dll 中调用函数。但我不知道如何编组指向作为状态的 C# 对象的指针。
为了将对象引用传递给我通过在此处搜索找到的 C 函数,否则似乎我需要一个结构类型才能编组到该函数,因此我创建了一个结构来保存我的对象:
[StructLayout(LayoutKind.Sequential)]
struct MyObjectState
{
public object state;
}
编辑:我尝试在 public object state 属性上添加一个属性:[MarshalAs(UnmanagedType.Struct, SizeConst = 4)],但这会产生相同的错误,所以我删除了它,但它似乎无论如何都不起作用。
该结构包含一个对象属性,用于保存回调函数的任何对象。
我在 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* 上找到了各种各样的东西,但没有什么能帮助我让它工作
谢谢。
【问题讨论】: