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

问题描述 投票:0回答:2

所以我正在研究这个名为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);
}
c# c arrays pointers byte
2个回答
0
投票

如果已声明返回类型为byte,则不能返回byte []数组。我没看到函数的签名应该是什么(例如,“unity_get_camera_screenshot_callback”的定义是什么?),但是你可以把它改成

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

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);
© www.soinside.com 2019 - 2024. All rights reserved.