将C#byte []传递给C char指针

时间:2018-03-03 16:09:59

标签: c# c arrays pointers byte

所以我正在处理这个名为cROS的c库,但是我想从C#中检索一个byte [],以便我可以使用该库共享它并且我在传递一个byte []时遇到问题到char *。

C#代码

[DllImport("aavatar")] private static extern void unity_reg_get_camera_screenshot_callback(unity_get_camera_screenshot_callback callback_fn);

private static byte get_camera_screenshot(int resWidth, int resHeight)
{
    ...
    byte[] bytes = screenShot.EncodeToPNG();
    return bytes;
}

void Start(){
...

unity_reg_get_camera_screenshot_callback(new unity_get_camera_screenshot_callback(get_camera_screenshot));
}

C代码

void unity_reg_get_obj_coordinate_callback(unity_get_obj_coordinate_callback callback_fn)
{
    Unity_get_obj_coordinate_fn= callback_fn;
}

CallbackResponse callback_srv_get_cam_screenshot(cRosMessage *request, cRosMessage *response, void* data_context)
{
    ...
    char *ret_cam_screenshot;
    ret_cam_screenshot = Unity_get_cam_screenshot_fn((int) scr_width32,(int)scr_height32);
}

1 个答案:

答案 0 :(得分:0)

好的,此互操作方案存在一些问题,因此我们将从byte[]开始。将字节数组编组为接受char*的非托管代码的方式是使用IntPtr,如下所示:

private static IntPtr funcCalledByNativeCode()
{
  byte[] bytes = getSomeBytes();
  IntPtr retVal = Marshal.AllocHGlobal(bytes.Length);
  Marshal.Copy(bytes, 0, retVal, bytes.Length);
  return retVal;
}

现在,这就是问题所在。调用Marshal.AllocHGlobal()分配的内存需要通过调用Marshal.FreeHGlobal()来释放。由于您使用了回调,可能最简单的方法是使用本机代码注册C风格的析构函数,只要它完成了一个互操作内存块就可以调用它。

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void InteropDtor(IntPtr pMem);

您将实施的目标如下:

private static void myInteropKiller(IntPtr allocatedMemory)
{
  Marshal.FreeHGlobal(allocatedMemory);
}

另一种(也是更简单的)方法是让本机代码在其旁边分配缓冲区并在回调函数中提供它,您只需填写托管端,如下所示:

private static void funcCalledByNativeCode(IntPtr buffer, ref int length)
{
  byte[] bytes = getSomeBytes();
  lenth = bytes.Length;
  if (bytes.Length <= length) // if this isn't enough, the native code can
                              // check 'length' for the required size
  {
    Marshal.Copy(bytes, 0, buffer, bytes.Length);
  }
}

另一个主要问题是,当从托管代码传递函数指针到本机代码时,您必须确保在非托管代码有机会使用它之前GC不会收集委托实例。通常,当您调用需要委托的方法时,您只需提供要使用的函数的名称。这将创建一个临时委托实例,GC将跟踪任何其他对象引用。问题是,如果您通过托管/非托管图层传递该代理,GC可能会丢失对它的所有引用,因此它将收集它。

因此,只要您有一个委托,您将作为回调传递给本机代码,除了使用UnmanagedFunctionPointer属性修饰委托定义之外,您还需要定义一个静态变量来保存实际的委托实施方法的参考。

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void Fn_CallbackFunction(IntPtr buffer, ref int length);

private static Fn_CallbackFunction CallbackOne = myCallback;

private static void myCallback(IntPtr buffer, ref int length)
{
  // implementation
}

// when calling the native function that wants the callback function
// pointer, use the variable, not the method name:

  nativeRegisterFunction(CallbackOne);