托管 C++,在 C# 和 C++ 之间架起一座桥梁
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1827102/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Managed C++ to form a bridge between c# and C++
提问by ist_lion
I'm a bit rusty, actually really rusty with my C++. Haven't touched it since Freshman year of college so it's been a while.
我有点生疏,实际上我的 C++ 真的生疏了。自从大学一年级以来就没有碰过它,所以已经有一段时间了。
Anyway, I'm doing the reverse of what most people do. Calling C# code from C++. I've done some research online and it seems like I need to create some managed C++ to form a bridge. Use __declspec(dllexport) and then create a dll from that and use the whole thing as a wrapper.
无论如何,我正在做与大多数人相反的事情。从 C++ 调用 C# 代码。我在网上做了一些研究,似乎我需要创建一些托管 C++ 来形成桥梁。使用 __declspec(dllexport) 然后从中创建一个 dll 并将整个事物用作包装器。
But my problem is - I'm really having a hard time finding examples. I found some basic stuff where someone wanted to use the C# version to String.ToUpper() but that was VERY basic and was only a small code snippet.
但我的问题是 - 我真的很难找到例子。我发现了一些基本的东西,有人想在 String.ToUpper() 中使用 C# 版本,但那是非常基本的,只是一小段代码片段。
Anyone have any ideas of where I can look for something a bit more concrete? Note, I do NOT want to use COM. The goal is to not touch the C# code at all.
任何人都知道我可以在哪里寻找更具体的东西?请注意,我不想使用 COM。目标是根本不接触 C# 代码。
采纳答案by CuppM
While lain beat me to writing an example, I'll post it anyhow just in case...
虽然 lain 让我写了一个例子,但我还是会发布它以防万一......
The process of writing a wrapper to access your own library is the same as accessing one of the standard .Net libraries.
编写包装器以访问您自己的库的过程与访问标准 .Net 库之一的过程相同。
Example C# class code in a project called CsharpProject:
名为 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);
}
}
}
You would create a managed C++ class library project (example is CsharpWrapper) and add your C# project as a reference to it. In order to use the same header file for internal use and in the referencing project, you need a way to use the right declspec. This can be done by defining a preprocessor directive (CSHARPWRAPPER_EXPORTS
in this case) and using a #ifdef
to set the export macro in your C/C++ interface in a header file. The unmanaged interface header file must contain unmanaged stuff (or have it filtered out by the preprocessor).
您将创建一个托管 C++ 类库项目(例如 CsharpWrapper)并将您的 C# 项目添加为对它的引用。为了在内部使用和引用项目中使用相同的头文件,您需要一种使用正确 declspec 的方法。这可以通过定义预处理器指令(CSHARPWRAPPER_EXPORTS
在本例中)并使用 a#ifdef
在头文件中的 C/C++ 接口中设置导出宏来完成。非托管接口头文件必须包含非托管内容(或由预处理器过滤掉)。
Unmanaged C++ Interface Header file (CppInterface.h):
非托管 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);
Then you can create an internal header file to be able to include in your managed library files. This will add the using namespace
statements and can include helper functions that you need.
然后您可以创建一个内部头文件,以便能够包含在您的托管库文件中。这将添加using namespace
语句并可以包含您需要的辅助函数。
Managed C++ Interface Header file (CsharpInterface.h):
托管 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;
}
Then you just write your interface code that does the wrapping.
然后你只需编写你的接口代码来进行包装。
Managed C++ Interface Source file (CppInterface.cpp):
托管 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());
}
Then just include the unmanaged header in your unmanaged project, tell the linker to use the generated .lib file when linking, and make sure the .Net and wrapper DLLs are in the same folder as your unmanaged application.
然后只需在非托管项目中包含非托管标头,告诉链接器在链接时使用生成的 .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());
}
回答by Iain
Create a new C++/CLI project in visual studio and add a reference to your C# dll. Assume we have a C# dll called DotNetLib.dll
with this class in:
在 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;
}
}
}
Now add a CLR C++ class to your C++/CLI project:
现在将 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;
}
};
}
This will call C# from C++.
这将从 C++ 调用 C#。
Now if needed you can add a native C++ class to your C++/CLI project which can talk to the CLR C++ class:
现在,如果需要,您可以将本机 C++ 类添加到您的 C++/CLI 项目中,该类可以与 CLR C++ 类对话:
// Native.h
#pragma once
class Native
{
public:
Native(void);
int Add(int a, int b);
~Native(void);
};
and:
和:
// 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);
}
You should be able to call the Native class from any other native C++ dll's as normal.
您应该能够像往常一样从任何其他本机 C++ dll 调用 Native 类。
Note also that Managed C++ is different to and was superceeded by C++/CLI. Wikipedia explains it best:
另请注意,托管 C++ 与 C++/CLI 不同并被 C++/CLI 取代。维基百科解释得最好: