我正在为本地库编写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可以自动转换结构?
答案 0 :(得分:1)
您的问题是char*
的{{1}}成员。 C#封送器假定它负责释放该内存。它通过调用struct
来实现。我认为很明显内存并不是要被C#代码破坏。
将该成员改为CoTaskMemFree
而不是:
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;
}
来读取字符串的值。
通过将成员设为私有并通过属性公开它们来解决此问题。这将允许您封装从指针到字符串的转换。