从 C++/CLI 函数调用 C# 函数
Calling C# function from a C++/CLI function
我的项目要求我使用 C# 为 C++ 提供用户界面。我调用的其中一个 C++ 函数完成了一系列工作,并通过另一个函数提供定期进度更新 "object." 下面是我的意思的示例。
C++
class AppDelegate : public ProgressDelegate
{
void AppDelegate::UpdateStatusText(const char* text)
{
// Go() will end up calling me at some point.
OutputDebugString(text);
}
void AppDelegate::ShowMessage(const char* text)
{
// Go() will end up calling me at some point.
OutputDebugString(text);
}
};
int CppWrapper::Go()
{
return cppInstance->Go()
}
CSharp
void UpdateStatusText(String text)
{
//update UI
}
void ShowMessage(String text)
{
//update UI
}
我想要做的是获取 updateStatusText 和 ShowMessage 并将文本传递给 C# 以更新我的 UI。我的问题是如何公开适当的 C# 方法,以便我的 C++ 代码可以调用它们?请注意,修改 Go 对我来说不是一个选项。
您必须将相关的 C# 代码构建到程序集中,然后在 C++ CLI 项目中引用该程序集。在 C++ CLI 包装器中,您将调用通过此 C# 程序集公开的函数,还将调用本机 C++ 代码。
C++ CLI 项目可以包含本机 C++ 代码,只需确保没有为本机文件启用 CLR 开关。所以,您将有 3 个项目 -
- 用于 GUI 的 C# 项目将调用 main.还引用了用于公开要通过 C++ 互操作调用的 C# 函数的程序集。
- 公开某些托管函数的 C# 程序集(因此可从 C++ CLI 调用)
- C++ CLI 项目,将包装并包含本机代码。
也许这个例子可以帮到你:
编写托管 DLL
要创建一个简单的托管 DLL,它有一个 public 方法来添加两个数字和 return 结果,请按照下列步骤操作:
启动 Microsoft Visual Studio .NET 或 Microsoft Visual Studio 2005。
在“文件”菜单上,指向“新建”,然后单击“项目”。 “新建项目”对话框打开。
在项目类型下,单击 Visual C# 项目。
注意在 Visual Studio 2005 中,单击项目类型下的 Visual C#。
在模板下,单击 Class 库。
在“名称”文本框中,键入 sManagedDLL,然后单击“确定”。
在代码视图中打开 Class1.cs 文件。
要声明具有将两个数字相加的方法的 public 接口,请将以下代码添加到 Class1.cs 文件:
// Interface declaration.
public interface ICalculator
{
int Add(int Number1, int Number2);
};
要在 class 中实现此 public 接口,请将以下代码添加到 Class1.cs 文件中:
// Interface implementation.
public class ManagedClass:ICalculator
{
public int Add(int Number1,int Number2)
{
return Number1+Number2;
}
}
注册托管 DLL 以用于 COM 或本机 C++
要将托管 DLL 与 COM 或本机 C++ 一起使用,您必须在 Windows 注册表中注册 DLL 的程序集信息。为此,请按照下列步骤操作:
从本机 C++ 代码调用托管 DLL
// Import the type library.
#import "..\ManagedDLL\bin\Debug\ManagedDLL.tlb" raw_interfaces_only
如果您计算机上的路径与此路径不同,请更改类型库的路径。
要声明要使用的命名空间,请将以下代码添加到 CPPClient.cpp 文件:
using namespace ManagedDLL;
完整代码清单
//Managed DLL
// Class1.cs
// A simple managed DLL that contains a method to add two numbers.
using System;
namespace ManagedDLL
{
// Interface declaration.
public interface ICalculator
{
int Add(int Number1, int Number2);
};
// Interface implementation.
public class ManagedClass:ICalculator
{
public int Add(int Number1,int Number2)
{
return Number1+Number2;
}
}
}
//C++ Client
// CPPClient.cpp: Defines the entry point for the console application.
// C++ client that calls a managed DLL.
#include "stdafx.h"
#include "tchar.h"
// Import the type library.
#import "..\ManagedDLL\bin\Debug\ManagedDLL.tlb" raw_interfaces_only
using namespace ManagedDLL;
int _tmain(int argc, _TCHAR* argv[])
{
// Initialize COM.
HRESULT hr = CoInitialize(NULL);
// Create the interface pointer.
ICalculatorPtr pICalc(__uuidof(ManagedClass));
long lResult = 0;
// Call the Add method.
pICalc->Add(5, 10, &lResult);
wprintf(L"The result is %d\n", lResult);
// Uninitialize COM.
CoUninitialize();
return 0;
}
参考:
How to call a managed DLL from native Visual C++ code in Visual Studio.NET or in Visual Studio 2005
或者,我曾经做的(在我切换到使用 P/Invoke 方法从 C# 调用到 C++ 之前)是有 3 个项目(如 StraightLine 所提到的)但我有 C#,托管C++ 和本机 C++,并让托管 C++ 成为我 bridge/proxy 在两者(本机 C++ 和 C#)之间进行对话。这样可以更轻松地在我的本机 C++ 端工作。需要注意的是,某些 STL(主要是容器)不受托管支持,或者有时 std::string(托管 C++ 版本)的行为在本机 C++ std::string 中使用时会导致异常,因此请注意支持托管 C++ 的 STL 库。
此外,正如 StraightLine 所提到的,桥接代码(在我的例子中是托管 C++)必须有一个包装器,它将从托管到本地编组,反之亦然(即你的 "const char*" 到 System.String,如果你的字符是 8 位等)
我的项目要求我使用 C# 为 C++ 提供用户界面。我调用的其中一个 C++ 函数完成了一系列工作,并通过另一个函数提供定期进度更新 "object." 下面是我的意思的示例。
C++
class AppDelegate : public ProgressDelegate
{
void AppDelegate::UpdateStatusText(const char* text)
{
// Go() will end up calling me at some point.
OutputDebugString(text);
}
void AppDelegate::ShowMessage(const char* text)
{
// Go() will end up calling me at some point.
OutputDebugString(text);
}
};
int CppWrapper::Go()
{
return cppInstance->Go()
}
CSharp
void UpdateStatusText(String text)
{
//update UI
}
void ShowMessage(String text)
{
//update UI
}
我想要做的是获取 updateStatusText 和 ShowMessage 并将文本传递给 C# 以更新我的 UI。我的问题是如何公开适当的 C# 方法,以便我的 C++ 代码可以调用它们?请注意,修改 Go 对我来说不是一个选项。
您必须将相关的 C# 代码构建到程序集中,然后在 C++ CLI 项目中引用该程序集。在 C++ CLI 包装器中,您将调用通过此 C# 程序集公开的函数,还将调用本机 C++ 代码。
C++ CLI 项目可以包含本机 C++ 代码,只需确保没有为本机文件启用 CLR 开关。所以,您将有 3 个项目 -
- 用于 GUI 的 C# 项目将调用 main.还引用了用于公开要通过 C++ 互操作调用的 C# 函数的程序集。
- 公开某些托管函数的 C# 程序集(因此可从 C++ CLI 调用)
- C++ CLI 项目,将包装并包含本机代码。
也许这个例子可以帮到你:
编写托管 DLL
要创建一个简单的托管 DLL,它有一个 public 方法来添加两个数字和 return 结果,请按照下列步骤操作:
启动 Microsoft Visual Studio .NET 或 Microsoft Visual Studio 2005。 在“文件”菜单上,指向“新建”,然后单击“项目”。 “新建项目”对话框打开。 在项目类型下,单击 Visual C# 项目。
注意在 Visual Studio 2005 中,单击项目类型下的 Visual C#。 在模板下,单击 Class 库。 在“名称”文本框中,键入 sManagedDLL,然后单击“确定”。 在代码视图中打开 Class1.cs 文件。 要声明具有将两个数字相加的方法的 public 接口,请将以下代码添加到 Class1.cs 文件:
// Interface declaration.
public interface ICalculator
{
int Add(int Number1, int Number2);
};
要在 class 中实现此 public 接口,请将以下代码添加到 Class1.cs 文件中:
// Interface implementation.
public class ManagedClass:ICalculator
{
public int Add(int Number1,int Number2)
{
return Number1+Number2;
}
}
注册托管 DLL 以用于 COM 或本机 C++ 要将托管 DLL 与 COM 或本机 C++ 一起使用,您必须在 Windows 注册表中注册 DLL 的程序集信息。为此,请按照下列步骤操作:
从本机 C++ 代码调用托管 DLL
// Import the type library.
#import "..\ManagedDLL\bin\Debug\ManagedDLL.tlb" raw_interfaces_only
如果您计算机上的路径与此路径不同,请更改类型库的路径。 要声明要使用的命名空间,请将以下代码添加到 CPPClient.cpp 文件:
using namespace ManagedDLL;
完整代码清单
//Managed DLL
// Class1.cs
// A simple managed DLL that contains a method to add two numbers.
using System;
namespace ManagedDLL
{
// Interface declaration.
public interface ICalculator
{
int Add(int Number1, int Number2);
};
// Interface implementation.
public class ManagedClass:ICalculator
{
public int Add(int Number1,int Number2)
{
return Number1+Number2;
}
}
}
//C++ Client
// CPPClient.cpp: Defines the entry point for the console application.
// C++ client that calls a managed DLL.
#include "stdafx.h"
#include "tchar.h"
// Import the type library.
#import "..\ManagedDLL\bin\Debug\ManagedDLL.tlb" raw_interfaces_only
using namespace ManagedDLL;
int _tmain(int argc, _TCHAR* argv[])
{
// Initialize COM.
HRESULT hr = CoInitialize(NULL);
// Create the interface pointer.
ICalculatorPtr pICalc(__uuidof(ManagedClass));
long lResult = 0;
// Call the Add method.
pICalc->Add(5, 10, &lResult);
wprintf(L"The result is %d\n", lResult);
// Uninitialize COM.
CoUninitialize();
return 0;
}
参考: How to call a managed DLL from native Visual C++ code in Visual Studio.NET or in Visual Studio 2005
或者,我曾经做的(在我切换到使用 P/Invoke 方法从 C# 调用到 C++ 之前)是有 3 个项目(如 StraightLine 所提到的)但我有 C#,托管C++ 和本机 C++,并让托管 C++ 成为我 bridge/proxy 在两者(本机 C++ 和 C#)之间进行对话。这样可以更轻松地在我的本机 C++ 端工作。需要注意的是,某些 STL(主要是容器)不受托管支持,或者有时 std::string(托管 C++ 版本)的行为在本机 C++ std::string 中使用时会导致异常,因此请注意支持托管 C++ 的 STL 库。
此外,正如 StraightLine 所提到的,桥接代码(在我的例子中是托管 C++)必须有一个包装器,它将从托管到本地编组,反之亦然(即你的 "const char*" 到 System.String,如果你的字符是 8 位等)