带有指向结构参数指针的 C# 本机回调
C# native callback with pointer to struct parameter
我正在为本机库编写 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#中的回调被触发,结构体成员具有预期值。
但是在 return 到本机代码时,会触发堆损坏异常 (0xc0000374)。
显然,我想避免这种情况。
如果我将 C# 回调签名更改为使用 IntPtr 而不是 "ref application_request" 参数,然后使用以下代码手动封送它,它就可以工作。
var request = Marshal.PtrToStructure<application_request>(requestptr);
但我希望签名尽可能精确,而不必自己使用封送拆收器。
我是否可以更改回调委托的签名以便 .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
.
来读取字符串的值
您通过将成员设为私有并通过属性公开它们来完成此操作。这将允许您封装从指针到字符串的转换。
我正在为本机库编写 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#中的回调被触发,结构体成员具有预期值。
但是在 return 到本机代码时,会触发堆损坏异常 (0xc0000374)。
显然,我想避免这种情况。
如果我将 C# 回调签名更改为使用 IntPtr 而不是 "ref application_request" 参数,然后使用以下代码手动封送它,它就可以工作。
var request = Marshal.PtrToStructure<application_request>(requestptr);
但我希望签名尽可能精确,而不必自己使用封送拆收器。
我是否可以更改回调委托的签名以便 .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
.
您通过将成员设为私有并通过属性公开它们来完成此操作。这将允许您封装从指针到字符串的转换。