2009-10-16 31 views
0

我有現有的C#代碼,簽名Foo(long[][] longs),我需要調用非託管C++而不是 C++/CLI)。我似乎無法弄清楚__gc[]__gc*的正確組合,以使編譯器感到滿意。如何從Managed C++(舊語法)調用Foo(long [] [])(C#)?

用C++/CLI,這是直接的:

std::vector<__int64> evens; 
evens.push_back(2); evens.push_back(4); evens.push_back(6); evens.push_back(8); 
std::vector<__int64> odds; 
odds.push_back(1); odds.push_back(3); odds.push_back(5); odds.push_back(7); 
std::vector<std::vector<__int64> > ints; 
ints.push_back(evens); ints.push_back(odds); 

array<array<__int64>^>^ mgdInts = gcnew array<array<__int64>^>(ints.size()); 
for (size_t i = 0; i<ints.size(); ++i) 
{ 
    const std::vector<__int64>& slice = ints[i]; 
    mgdInts[i] = gcnew array<__int64>(slice.size()); 
    for (size_t j=0; j<slice.size(); ++j) 
     mgdInts[i][j] = slice[j]; 
} 

編輯:由於我使用Visual Studio 2008中, 「簡單」 的解決辦法是把C++/CLI代碼在其自己的文件和編譯與/clr;當然,如果我不必這樣做(例如,使用Managed C++的其他.h文件),它會更容易。 C#代碼無法更改,因爲它是從Web引用自動生成的。

回答

0

我想出了一個解決方案是使用List<>.ToArray()

System::Collections::Generic::List<__int64 __gc[]>* mgdInts = new System::Collections::Generic::List<__int64 __gc[]>(ints.size()); 
for (size_t i = 0; i<ints.size(); ++i) 
{ 
    const std::vector<__int64>& slice = ints[i]; 
    __int64 mgdSlice __gc[] = new __int64 __gc[slice.size()]; 
    for (size_t j=0; j<slice.size(); ++j) 
     mgdSlice[j] = slice[j]; 

    mgdInts->Add(mgdSlice); 
} 

ClassLibrary1::Class1::Foo(mgdInts->ToArray()); 
0

變化從這個 美孚(長[] []多頭) 此簽名: 美孚(陣列多頭)

然後,當你看看OLEView.exe這類所得的類型庫,你應該看到:

HRESULT Foo([in] SAFEARRAY(int64) longs); 

從C++,這是相當直接的調用。你可以只用Win32來創建一個SAFEARRAY,或者我建議包含,然後在ATL中使用CComSafeArray包裝類。儘管C#和C++都有更豐富的數組定義,但兩者之間的互操作性通常是通過類型庫編組器完成的,其中99%是遺留的,並且基於「VB兼容」。 Type Library編組器支持的唯一數組類型是SAFEARRAY,所以當你按照正常的方式完成所有這些時,這就是你所得到的。

但是,COM支持更豐富的數組系統(符合數組),C#可以理解,這很難做到,並且不能簡單地重新設置C#DLL並在非託管C++程序中使用生成的類型庫。一些技巧需要用ILDASM調整C#代碼。其他人要求你保持接口的兩個定義,一個用C++語言,一個用C#,並確保它們同步(無法將一個轉換爲另一個),然後在C++的IDL中用size_is裝飾參數,並在C#與MarshalAs。這是一個混亂,真正的人們這樣做的唯一的類型是,如果他們有一個已發佈的遺留界面,他們不能改變。如果這是你的C#代碼,你可以定義接口,我不會去那裏。儘管如此,該技術仍然可用。這裏有一個參考:http://support.microsoft.com/kb/305990 如果你以前從來沒有做過這樣的事情,那麼預計大概需要一個星期左右才能完成。

+0

的C#代碼「不能」的變化,我想編寫一個文件,/ CLR(VS 2008)可能是更直接的比這個。 – 2009-10-16 21:18:59

+0

是的。 如果由於某種原因你不想要任何C++/CLR代碼,那麼解決它的另一種方法是創建另一個可以控制的C#對象,它具有符合類型庫的接口幷包裝原始代碼。 – zumalifeguard 2009-10-16 23:54:31