gcroot 和 /clr 混合模式和 C++ 包装器是从纯 C 到 C# 的最短路径吗?

本文关键字:最短路径 混合 clr 模式 C++ 包装 gcroot | 更新日期: 2023-09-27 18:37:22

所以我正在编写一个纯C的插件DLL(以及一堆外来包含),但大多数实际代码都在现有的C#类库中。我正在寻找从 C(不是 C++)到 C# 的最短路径。外国包括不是C++安全。

周围有成堆的样品供C++使用,而对于纯C而言则不多。

似乎我应该能够将整个DLL编译为/clr,但不能编译C;然后在同一个DLL中包含C++包装器,该包装器提供C API,但包含用于调用C#类的托管代码。

因此,实例化 C# 类并将其挂在 C++ 类的 gcroot 中,并将 C++ 类指针作为 void* 传递回 C 代码以备将来调用。

有很多细节需要正确处理,但不是那么多代码。有没有更好的方法?


认为是时候添加一些代码了。

// Wrapper.h
#pragma once
// API for call by C
#ifdef __cplusplus
extern "C" {
#endif
    void* wrap_create();
    void wrap_doit(void* wrapper, char* input, char* output, int maxlen);
#ifdef __cplusplus
}
#endif
// Wrapper.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <vcclr.h>
#include "Wrapper.h"
using namespace System;
class Wrapper {
public:
    gcroot<Wrappee::Evaluator^> eval;
    Wrapper() {}
};
void* wrap_create() {
    Wrapper* w = new Wrapper();
    w->eval = gcnew Wrappee::Evaluator();
    return w;
}
void wrap_doit(void* wrapper, char* input, char* output, int maxlen) {
    Wrapper* w = (Wrapper*)wrapper;
    String^ s = w->eval->Doit(gcnew String(input));
    pin_ptr<const wchar_t> wch = PtrToStringChars(s);
    wcstombs(output, wch, maxlen);
}
// Wrappee.cs
using System;
namespace Wrappee {
  public class Evaluator {
    string _s;
    public static Evaluator Create() {
      return new Evaluator {
        _s = "wrapped evaluator"
      };
    }
    public string Doit(string s) {
      return _s + ":" + s;
    }
  }
}

为什么这行不通?代码基于以下链接:https://msdn.microsoft.com/EN-US/library/481fa11f%28v=VS.140,d=hv.2%29.aspx。


gcroot 和 /clr 混合模式和 C++ 包装器是从纯 C 到 C# 的最短路径吗?

答案是否定的,那行不通。托管类依赖于 CLR 运行时,该运行时需要由应用程序承载。对于自动发生的托管应用(mscoree.dll启动期间),但对于本机应用,没有主机,因此没有 CLR。

所以我们必须提供一个。正如@hanspassant有帮助地指出的那样,这是"反向P/调用",它确实是不同的。您必须通过COM托管接口到达那里,特别是ICLRMetaHost

好消息是,这里有一个示例来展示它是如何完成的:https://code.msdn.microsoft.com/windowsdesktop/CppHostCLR-e6581ee0。

还有其他示例:搜索CppHostCLR