简体   繁体   English

C#本机回调,带有指向struct参数的指针

[英]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 . 您的问题是structchar*成员。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM