带有指向结构参数指针的c#本机回调
本文关键字:本机 回调 指针 参数 结构 | 更新日期: 2023-09-27 18:12:44
我正在为一个本机库编写一个c#包装器。它包含以下回调函数:
typedef application_event_result(*application_event_ptr)(application_request* request);
参数定义如下:
typedef struct {
uint32_t query;
const char* client;
bool isAuthenticated;
bool isGuest;
} application_request;
我已经像这样定义了c#回调委托:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate application_event_result application_event([MarshalAs(UnmanagedType.Struct)]
ref application_request request);
c#中的结构:
[StructLayout(LayoutKind.Sequential)]
public struct application_request
{
public UInt32 query;
[MarshalAs(UnmanagedType.LPStr)]
public string client;
[MarshalAs(UnmanagedType.I1)]
public bool isAuthenticated;
[MarshalAs(UnmanagedType.I1)]
public bool isGuest;
}
这一切似乎工作。c#中的回调被触发,并且该结构体的成员具有预期的值。
但是当返回到本机代码时,会触发堆损坏异常(0xc0000374)。
显然,我想避免那样。
如果我将c#回调签名改为使用IntPtr而不是"ref application_request"参数,然后使用以下代码手动封送它,它就可以工作了。
var request = Marshal.PtrToStructure<application_request>(requestptr);
但是我希望签名尽可能精确,而不必自己使用Marshaler。
是否有一个远离我改变回调委托的签名,所以。net可以自动转换结构?
您的问题是struct
中的char*
成员。c#封送程序假定它负责释放内存。它通过调用CoTaskMemFree
来实现。我认为很明显,c#代码根本不打算破坏内存。
将该成员封送为IntPtr
:
[StructLayout(LayoutKind.Sequential)]
public struct application_request
{
public UInt32 query;
public IntPtr client;
[MarshalAs(UnmanagedType.I1)]
public bool isAuthenticated;
[MarshalAs(UnmanagedType.I1)]
public bool isGuest;
}
在你的回调方法中你可以通过调用Marshal.PtrToStringAnsi
来读取字符串的值。
可以通过将成员设为私有并通过属性公开它们来完成。这将允许您封装从指针到字符串的转换。