2013-02-11 16 views
1

比方說,我有原型編組浮法[] []爲float **

int someFunction(const float ** raws) 

我如何可以調用這個函數與C#一個float[][]參數C++函數?可能沒有使用不安全的代碼。

+4

'float [] []'與'float **'根本不同,所以可能不會。 – 2013-02-11 00:21:52

+2

好吧,它不應該是不可能的。我確信有一種方法。這就是我稱之爲「編組」的原因。 – hattenn 2013-02-11 00:22:44

+0

我的意思是這樣做的方法是將float [] []放入類/結構體中,然後將其傳遞。 – 2013-02-11 00:25:03

回答

3

就我所知,你必須自己完成大部分工作。 Interop將幫助您編排頂層數組,但是您將完成所有嵌套數組的固定工作,然後在完成後取消固定。此代碼顯示做到這一點的一種方法:

using System; 
using System.Runtime.InteropServices; 

namespace ManagedClient 
{ 
    class Program 
    { 
     [DllImport("UnmanagedDll.dll", CallingConvention = CallingConvention.StdCall)] 
     private static extern int UseFloats([MarshalAs(UnmanagedType.LPArray)] IntPtr[] raws); 

     static void Main(string[] args) 
     { 
      float[][] data = 
      { 
       new[] { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f }, 
       new[] { 1.0f, 1.1f, 1.2f, 1.3f }, 
       new[] { 2.0f }, 
       new[] { 3.0f, 3.1f } 
      }; 

      var handles = new GCHandle[data.Length]; 
      var pointers = new IntPtr[data.Length]; 

      try 
      { 
       for (int i = 0; i < data.Length; ++i) 
       { 
        var h = GCHandle.Alloc(data[i], GCHandleType.Pinned); 
        handles[i] = h; 
        pointers[i] = h.AddrOfPinnedObject(); 
       } 

       UseFloats(pointers); 
      } 
      finally 
      { 
       for (int i = 0; i < handles.Length; ++i) 
       { 
        if (handles[i].IsAllocated) 
        { 
         handles[i].Free(); 
        } 
       } 
      } 
     } 
    } 
} 

這建立一個指針數組,其中每一個指向在所述輸入陣列中的數據float。 (這是C函數期望數據到達的格式。)您的C代碼如何知道每個子陣列的長度取決於您。在我的測試代碼,我只是硬編碼它以匹配傳入的C#代碼:

__declspec(dllexport) int __stdcall UseFloats(const float ** raws) 
{ 
    printf("%f %f %f %f %f\n", raws[0][0], raws[0][1], raws[0][2], raws[0][3], raws[0][4]); 
    printf("%f %f %f %f\n", raws[1][0], raws[1][1], raws[1][2], raws[1][3], raws[0][4]); 
    printf("%f\n", raws[2][0]); 
    printf("%f %f\n", raws[3][0], raws[3][1]); 
    return 0; 
} 

在現實中你可能會想要做的事情告訴了非託管代碼多久,每個子陣列是 - 您選擇的非託管函數簽名不會讓被調用的代碼知道每個子數組的長度。 (推測你使用float **的原因是因爲你想要鋸齒狀的數組,如果沒有,並且如果每個子數組的長度完全相同,那麼在這裏使用矩形數組會更有效率,而不是指針,這將使編組更容易太)。

+0

很好的答案。你可能的意思是「可能你使用float [] []」的原因不是「float **」,應該用下劃線或粗體表示,因爲如果是這種情況,可以自動編組二維數組(float [,])。 – 2013-02-11 10:56:41

+0

謝謝!但我的意思是我寫了:我責怪「float **」,因爲這是他試圖調用的非託管函數的簽名。這是造成問題的根本原因。 (如果非託管簽名繼續爲float,切換到C#中的float [,]並不會有多大幫助** - 非託管簽名需要一個指針數組,這是問題的核心,以float [,]開頭意味着你只需要固定一個對象,但你仍然需要構建一個IntPtr []。)我認爲最好的解決方案是如果可能的話更改非託管簽名。 – 2013-02-11 13:34:43

+0

@Ian爲什麼你使用'[MarshalAs(UnmanagedType.LPArray)]'?另外,如果您不使用該屬性,那麼默認的編組是什麼? – hattenn 2013-02-11 17:36:04

1

伊恩已經回答了你的問題,我只想建議在C++端使用SAFEARRAY。

SAFEARRAY是C/C++中模糊數組定義問題的COM答案,它們是包含底層元素的數量和大小的結構,並且與.Net數組更匹配。使用它們將允許從C#自動封送數組。

SAFEARRAY在C++中使用起來很痛苦,但ATL有一些很好的包裝讓事情變得更簡單。如果在所有可能的情況下改變C++函數來使用它,或者考慮編寫一個與使用它們的.Net互操作的C++包裝器,並且使用C++編寫編組代碼。

+0

不幸的是,C++代碼是由其他人編寫的,我沒有太多的控制權。雖然欣賞這個建議! – hattenn 2013-02-11 17:42:56

相關問題