2009-12-01 48 views
11

我有點生疏,實際上與我的C++生鏽。自從大學一年級以來沒有接觸過它,所以它已經有一段時間了。託管C++以形成C#和C++之間的橋樑

無論如何,我正在做與大多數人所做的相反的事情。從C++調用C#代碼。我在網上做了一些研究,似乎我需要創建一些託管C++來形成橋樑。使用__declspec(dllexport),然後從中創建一個dll並使用整個東西作爲包裝。

但我的問題是 - 我真的很難找到例子。我發現了一些基本的東西,有人想把C#版本用於String.ToUpper(),但這非常基本,只是一小段代碼片段。

任何人有任何想法,我可以尋找一些更具體的東西?請注意,我不想使用COM。目標是根本不觸碰C#代碼。

+0

您想暴露給非託管C/C++的接口有多複雜? – CuppM 2009-12-01 16:35:55

+0

看到這個鏈接的相似問題/答案:http://stackoverflow.com/questions/13293888/how-to-call-ac-sharp-library-from-native-c-using-c-cli-and-ijw 。 – amalgamate 2014-07-08 13:46:03

回答

11

雖然LAIN打我寫一個例子,不管怎樣,我萬一它張貼...

寫的包裝來訪問你自己的庫的過程與訪問標準.Net庫之一相同。在一個名爲CsharpProject項目

實例C#類代碼:

using System; 

namespace CsharpProject { 
    public class CsharpClass { 
     public string Name { get; set; } 
     public int Value { get; set; } 

     public string GetDisplayString() { 
      return string.Format("{0}: {1}", this.Name, this.Value); 
     } 
    } 
} 

您可以創建一個託管C++類庫項目(例如是CsharpWrapper),並添加C#項目作爲它的一個引用。爲了在內部使用和引用項目中使用相同的頭文件,您需要一種使用正確的declspec的方法。這可以通過定義預處理器指令(在這種情況下爲CSHARPWRAPPER_EXPORTS)並使用#ifdef在C/C++接口中的頭文件中設置導出宏來完成。非託管接口頭文件必須包含非託管內容(或者由預處理器過濾掉)。

非託管C++接口頭文件(CppInterface。h):

#pragma once 

#include <string> 

// Sets the interface function's decoration as export or import 
#ifdef CSHARPWRAPPER_EXPORTS 
#define EXPORT_SPEC __declspec(dllexport) 
#else 
#define EXPORT_SPEC __declspec(dllimport) 
#endif 

// Unmanaged interface functions must use all unmanaged types 
EXPORT_SPEC std::string GetDisplayString(const char * pName, int iValue); 

然後,您可以創建一個內部頭文件,以便能夠包含在託管庫文件中。這將添加using namespace語句,並可以包含您需要的幫助函數。

託管C++接口頭文件(CsharpInterface.h):

#pragma once 

#include <string> 

// .Net System Namespaces 
using namespace System; 
using namespace System::Runtime::InteropServices; 

// C# Projects 
using namespace CsharpProject; 


////////////////////////////////////////////////// 
// String Conversion Functions 

inline 
String^ToManagedString(const char * pString) { 
return Marshal::PtrToStringAnsi(IntPtr((char *) pString)); 
} 

inline 
const std::string ToStdString(String^strString) { 
IntPtr ptrString = IntPtr::Zero; 
std::string strStdString; 
try { 
    ptrString = Marshal::StringToHGlobalAnsi(strString); 
    strStdString = (char *) ptrString.ToPointer(); 
} 
finally { 
    if (ptrString != IntPtr::Zero) { 
    Marshal::FreeHGlobal(ptrString); 
    } 
} 
return strStdString; 
} 

然後你只寫你的界面代碼,做包裝。

託管C++接口源文件(CppInterface.cpp):

#include "CppInterface.h" 
#include "CsharpInterface.h" 

std::string GetDisplayString(const char * pName, int iValue) { 
CsharpClass^oCsharpObject = gcnew CsharpClass(); 

oCsharpObject->Name = ToManagedString(pName); 
oCsharpObject->Value = iValue; 

return ToStdString(oCsharpObject->GetDisplayString()); 
} 

然後,只需在您的非託管項目的非託管標題,鏈接時告訴使用生成的.lib文件鏈接,並確保.net和包裝器DLL與非託管應用程序位於同一文件夾中。

#include <stdlib.h> 

// Include the wrapper header 
#include "CppInterface.h" 

void main() { 
// Call the unmanaged wrapper function 
std::string strDisplayString = GetDisplayString("Test", 123); 

// Do something with it 
printf("%s\n", strDisplayString.c_str()); 
} 
+0

你解釋了一些事情 - 希望我可以選擇兩個答案。謝謝! – 2009-12-01 17:12:57

+0

字符串是一個很好的例子,因爲只要您需要將字符串從本地編碼到託管字符串(通常在大多數互操作中通常很快就會很快),就需要轉換函數 – Iain 2009-12-01 17:19:13

+0

對於「無此類文件或目錄」,您需要要麼:1)添加'CppInterface.h'到非託管應用程序。如果所有項目都位於同一位置/存儲庫中,我不會這樣做。因爲你有重複的文件來維護。 2)在非託管應用程序的編譯包含文件夾下添加包裝項目文件的路徑。對於Visual Studio,右鍵單擊該項目並選擇「屬性」。然後在「配置屬性」 - >「C/C++」 - >「常規」 - >「其他包含目錄」下,將路徑添加到「CppInterface.h」的位置。 – CuppM 2009-12-01 21:14:03

10

在visual studio中創建一個新的C++/CLI項目並添加一個對C#dll的引用。假設我們在這個類中調用DotNetLib.dll一個C#DLL:

namespace DotNetLib 
{ 
    public class Calc 
    { 
     public int Add(int a, int b) 
     { 
      return a + b; 
     } 
    } 
} 

現在添加一個CLR C++類的C++/CLI項目:

// TestCPlusPlus.h 

#pragma once 

using namespace System; 
using namespace DotNetLib; 

namespace TestCPlusPlus { 

    public ref class ManagedCPlusPlus 
    { 
    public: 
     int Add(int a, int b) 
     { 
      Calc^ c = gcnew Calc(); 
      int result = c->Add(a, b); 
      return result; 
     } 
    }; 
} 

這將調用C#從C++。

現在,如果需要,您可以添加本地C++類的C++/CLI項目,可以跟CLR C++類:

// Native.h 
#pragma once 

class Native 
{ 
public: 
    Native(void); 
    int Add(int a, int b); 
    ~Native(void); 
}; 

和:

// Native.cpp 
#include "StdAfx.h" 
#include "Native.h" 
#include "TestCPlusPlus.h" 

Native::Native(void) 
{ 
} 

Native::~Native(void) 
{ 
} 

int Native::Add(int a, int b) 
{ 
    TestCPlusPlus::ManagedCPlusPlus^ c = gcnew TestCPlusPlus::ManagedCPlusPlus(); 
    return c->Add(a, b); 
} 

您應該能夠像任何其他本地C++ dll一樣,調用Native類。

還要注意,託管C++與C++/CLI不同並且被C++/CLI取代。維基百科最能解釋它: