簡體   English   中英

將C#byte []傳遞給C char指針

[英]Passing C# byte[] to C char pointer

因此,我正在研究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);
}

如果已聲明字節的返回類型,則不能返回byte []數組。 我看不到該函數的簽名應該是什么(即,“ unity_get_camera_screenshot_callback”的定義是什么?),但是可能您可以將其更改為

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

好的,這種互操作方案存在一些問題,因此我們從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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM