2010-04-09 145 views
7

因此,我所擁有的是包含在* .dll中的C++ API,並且我想使用C#應用程序來調用API中的方法。將C++ API暴露給C#

到目前爲止,我已經創建了一個C++/CLR項目,包括本地C++ API和管理,以創建一個「橋」類,它看起來有點像下面這樣:

// ManagedBridge.h 
#include <CoreAPI.h> 
using namespace __CORE_API; 

namespace ManagedAPIWrapper 
{ 
    public ref class Bridge 
    { 
     public: 
      int    bridge_test(void); 
      int    bridge_test2(api_struct* temp); 
    } 
} 

// ManagedBridge.cpp 
#include <ManagedBridge.h> 

int Bridge::bridge_test(void) 
{ 
    return test(); 
} 

int Bridge::bridge_test2(api_struct* temp) 
{ 
    return test2(temp); 
} 

我也有具有到C++/CLR「Bridge.dll」的引用,然後使用包含內的方法C#應用程序。我有許多問題與此:

  1. 我無法弄清楚如何調用bridge_test2的C#程序中,因爲它沒有一個什麼樣的api_struct實際上就是知識。我知道我需要在某個地方編組對象,但是我在C#程序還是C++/CLR橋中執行?
  2. 這看起來像一個暴露API中所有方法的囉嗦方式,有沒有更容易的方式,我錯過了? (不使用的P/Invoke!)

編輯:好了,我已經得到了現在的工作得益於以下反應的基礎知識,但我的結構(稱之爲「api_struct2」在這個例子中)在C++的本機代碼既有本地枚舉和工會,如下所示:

typedef struct 
{ 
    enum_type1 eEnumExample; 
    union 
    { 
      long  lData; 
      int  iData; 
      unsigned char ucArray[128]; 
      char  *cString; 
      void  *pvoid; 
    } uData; 
} api_struct2; 

我想我已經找到了如何讓枚舉工作;我已經在託管代碼中重新聲明瞭它,並且正在執行「native_enum test = static_cast(eEnumExample)」以將託管版本切換爲本機。

然而,工會讓我難住,我不太確定如何攻擊它..想法任何人?

回答

3

是的,你通過引用傳遞一個非託管結構。這對於C#程序來說是個問題,指針與垃圾回收非常不兼容。不包括它可能沒有結構聲明的事實。

可以通過聲明結構的託管版本解決這個問題:

public value struct managed_api_struct { 
    // Members... 
}; 

現在你可以聲明方法

int bridge_test2(managed_api_struct temp); // pass by value 

int bridge_test2(managed_api_struct% temp); // pass by reference 

選擇後者,如果該結構具有超過4個字段(~16字節)。該方法需要將結構成員一個接一個地複製到非託管的api_struct中,並調用非託管的類方法。這是不幸的,因爲託管結構的內存佈局是不可預測的。

這是非常機械的,你可能會得到幫助from SWIG。我自己並沒有使用它,不確定它是否足夠聰明來處理通過的結構。

一個完全不同的方法是通過給它一個構造函數和/或屬性讓包裝類更清潔,讓它可以構建api_struct的內容。或者你可以爲結構聲明一個wrapper ref類,就像在託管代碼中一樣。

+0

那麼這是否意味着我在C++/CLI * .dll或C#代碼本身中創建了managed_api_struct?另外,我認爲只要您使用StructLayout屬性,就可以將託管結構傳遞給本機代碼? – Siyfion 2010-04-12 07:43:28

+0

這並不重要,但C++/CLI可以避免循環依賴。是的,[StructLayout]可以工作,但是你必須使用Marshal :: StructureToPtr()調用。託管結構的佈局不可預測。 – 2010-04-12 10:26:18

+0

好的,謝謝,我現在就去看看,看看我在哪裏。 – Siyfion 2010-04-12 13:10:11

2

,因爲它沒有一個什麼樣的api_struct實際上是

您需要在.NET程序集定義一個託管版本的知識,使用屬性(如StructLayoutAttribute),以確保其正確編組。

這似乎是一個很囉嗦[...]

另一種方法是建立在你的API COM包裝(例如使用ATL)。這可能會更加努力,但至少可以避免P/Invoke所需的結構和函數定義的雙重編碼。

修正:您已經創建了一個C++/CLI項目:所以只需要添加正確的「的#pragma」來告訴編譯器,這是.NET代碼,然後將輸出的是C#項目可以直接引用的組件。

+0

什麼將添加#pragma幫助我?是否有任何方法可以將所有編組放在C++/CLI項目中,以便引用它的每個項目都不必重新聲明相應的.NET結構/類? – Siyfion 2010-04-09 10:10:57

+0

@Siyfion:'#pragma managed'允許切入和切出託管代碼。請參閱http://msdn.microsoft.com/en-us/library/0adb9zxe(VS.100).aspx – Richard 2010-04-09 10:37:11

+0

我明白,但它目前工作,所以我不明白什麼添加,將使我能做! ? – Siyfion 2010-04-09 10:38:15

2

尤奧正試圖做到這一點更復雜,它確實是。你想要的是兩個不同的結構。一個管理和一個非託管。您從外部公開受管版本(到您的C#應用​​程序)。這將是所有「.Net-ish」,沒有任何工會的概念。

在您的網橋中,您會收到管理版本的結構,手動創建非託管結構並編寫代碼以將數據逐字段移至非託管結構。然後調用您的非託管代碼,最後將數據移回託管結構。

有關C++/CLI的美妙之處在於託管代碼還可以處理非託管代碼和數據(幷包含非託管的.h文件)。