所以我正在处理这个名为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);
}
答案 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);