[英]C# native callback with pointer to struct parameter
I'm writing a C# wrapper for a native library. 我正在为本地库编写C#包装器。 It contains this callback function: 它包含以下回调函数:
typedef application_event_result(*application_event_ptr)(application_request* request);
The parameter is defined as such: 参数的定义如下:
typedef struct {
uint32_t query;
const char* client;
bool isAuthenticated;
bool isGuest;
} application_request;
I have defined the C# callback delegate like this: 我已经定义了C#回调委托,如下所示:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate application_event_result application_event([MarshalAs(UnmanagedType.Struct)]
ref application_request request);
The structure in C#: 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;
}
This all seems to work. 这一切似乎都起作用。 The callback in C# is triggered, and the members of the struct have the expected values. C#中的回调被触发,并且结构的成员具有期望的值。
But upon return to native code, a heap corruption exception is triggered (0xc0000374). 但是,返回到本机代码后,将触发堆损坏异常(0xc0000374)。
Obviously, I would like to avoid that. 显然,我想避免这种情况。
If I change the C# callback signature to use IntPtr instead of the "ref application_request" parameter, and then Marshal it manually using the following code it works. 如果我将C#回调签名更改为使用IntPtr而不是“ ref application_request”参数,然后使用以下代码手动将其编组,则它将起作用。
var request = Marshal.PtrToStructure<application_request>(requestptr);
But I would like to have the signature be as precise as possible and not have to use the Marshaler myself. 但是我希望签名尽可能精确,而不必亲自使用Marshaler。
Is there a away for me to change the callback delegate's signature so .net can convert the struct automatically? 我是否可以更改回调委托的签名,以便.net可以自动转换结构?
Your problem is the char*
member of the struct
. 您的问题是struct
的char*
成员。 The C# marshaler assumes that it is responsible for deallocating that memory. C#封送处理程序假定它负责重新分配该内存。 It does so by calling CoTaskMemFree
. 通过调用CoTaskMemFree
。 I think it is pretty clear that the memory is not meant to be destroyed by the C# code at all. 我认为很明显,该内存根本不打算被C#代码破坏。
Marshal that member as IntPtr
instead: 将该成员封为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;
}
Inside your callback method you can read the value of the string by calling Marshal.PtrToStringAnsi
. 在回调方法中,您可以通过调用Marshal.PtrToStringAnsi
来读取字符串的值。
You wrap this up by making the members private and exposing them via properties. 您可以通过将成员设为私有并通过属性将其公开来进行包装。 That will allow you to encapsulate the conversion from pointer to string. 这将允许您封装从指针到字符串的转换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.