c++ - 如何链接到 C++/Cli 混合模式 dll 中的 native 类

标签 c++ .net interop c++-cli mixed-mode

我有以下设置:

  • CSharp.dll,一个 C# dll
  • CppCli.dll,一个混合模式 C++/Cli dll。
  • Native.dll,原生 C++ dll。

native 项目声明

class Native
{
public:
    virtual void Add(int a);
};

在混合模式项目中实现:

class Mixed : public Native
{
public:
    virtual void Add(int a);
    ICSharpInterface^ MakeManaged();  
};

由于基类是在 Native 中定义的,所以我可以将我的实现传递给 Native 中的其他代码。但是现在我想测试这个类。

如果我使用 #pragma make_public(Mixed); 它只会公开一个结构,没有任何函数对外部可见。

如果我尝试从另一个混合模式 dll 链接到混合模式 dll,我会收到链接器错误,因为它是 native 类,而混合模式 dll 不生成要链接的 .lib。

如果我尝试 __declspec(dllexport) 类,Visual Studio 会提示,因为接口(interface)公开了托管内容。

所以我的问题是:

如何在我的测试中实例化(链接到)这个类?我对任何展示如何创建一个我可以调用其公共(public)接口(interface)的实例的解决方案都很满意,无论是来自 C++、C++/Cli 还是来自 C#。

最佳答案

您错过了重要的一步,您还没有考虑 native 程序将如何创建 Mixed 对象的实例。这很重要,它确实需要加载和初始化 CLR,以便它可以执行托管代码。请记住,客户端代码不会自动执行此操作,它不知道有关 CLR 的 bean,它只知道 Native.dll。可以通过三种基本方法来完成此操作:

  • 您可以将托管类公开为 COM 对象,使用 [ComVisible] 属性非常简单。可以直接从 C# 执行,不需要 C++/CLI 包装器。通常的缺点是客户端代码必须使用 COM 来实例化对象并对其进行调用,而不是程序员喜欢编写的那种代码。
  • 您可以自己托管 CLR,这是最高效、最灵活的解决方案。 This magazine article提供介绍,注意它已过时。
  • C++/CLI 编译器为您提供了一种方法,可以为您提供可以执行托管代码的非托管导出函数。如有必要,它会自动生成一个 stub ,用于加载和初始化 CLR。​​

稍微关注最后一点,因为那是您可能喜欢的,您在这里需要的是一个工厂函数,它创建一个 Mixed 类的实例并将 Native* 返回给调用者。所以它可以调用 ptr->Add() 并调用 Mixed::Add()。这看起来像这样:

extern "C" __declspec(dllexport)
Native* CreateObject() {
    return new Mixed;
}

还为您提供了可在您的 native 项目中链接的导入 .lib。请注意缺点,它们很重要。它并不是很快,因为 stub 必须检查 CLR 是否已初始化并进行 native 到托管的转换。错误报告非常糟糕,因为您没有合适的方法来诊断 C# 代码中抛出的异常。内存管理是一个问题,调用者必须能够成功销毁返回的对象,这需要所有模块使用完全相同的 CRT。 COM 解决的问题类型。

通过使用 IL 重写器,在 C# 中也可以使用完全相同的技术。吉塞克的 unmanaged exports模板很受欢迎。

关于c++ - 如何链接到 C++/Cli 混合模式 dll 中的 native 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22195717/

相关文章:

c# - 如何使用 WCHAR* 在消息框中显示来自 C# 的 C 函数

c++ - 打开简历。 detectMultiScale() 函数返回错误

c++ - 如何使用 MAPI 从个人资料中获取电子邮件地址

c# - 要求基类的子级从基类调用方法的设计模式

c# - C# winform 中的滚动容器

pdf - 有什么工具可以把word和excel转成PDF吗?

c# - QuickBooks: Unresolved SDK 引用?

c++ - 保持 shared_ptr use_count() 为 1

c++ - 运算符重载时未解析的外部符号

c# - variable.ToString() 与 Convert.ToString(variable)