托管C ++以形成c#和C ++之间的桥梁

我有点生疏,实际上我的C ++真的很生疏。 从大学一年级开始就没有触及它,所以已经有一段时间了。

无论如何,我正在做与大多数人相反的事情。 从C ++调用C#代码。 我在网上做了一些研究,似乎我需要创建一些托管C ++来形成一个桥梁。 使用__declspec(dllexport)然后从中创建一个dll并使用整个东西作为包装器。

但我的问题是 – 我真的很难找到例子。 我找到了一些基本的东西,有人想将C#版本用于String.ToUpper(),但这是非常基本的,只是一个小代码片段。

任何人都有任何想法,我可以在哪里寻找更具体的东西? 注意,我不想使用COM。 目标是根本不触及C#代码。

虽然lain打我写一个例子,但无论如何我都会发布以防万一……

编写包装器以访问您自己的库的过程与访问其中一个标准.Net库相同。

示例C#类代码在名为CsharpProject的项目中:

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  // 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  // .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  // 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()); } 

在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类。

另请注意,Managed C ++与C ++ / CLI不同并且已被C ++ / CLI取代。 维基百科解释得最好:

http://en.wikipedia.org/wiki/C%2B%2B/CLI