2009-12-01 40 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取代。维基百科最能解释它: