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

Is gcroot and /clr mixed mode and a C++ wrapper the shortest path from pure C to C#?

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

有大量 C++ 样本,纯 C 样本不多。

看来我应该可以将整个 DLL 编译为 /clr,但不能将 C 编译为;然后在同一个 DLL 中包含一个 C++ 包装器,该包装器呈现 C API 但包含调用 C# class.

的托管代码

因此实例化 C# class 并在 C++ class 的 gcroot 中挂起它,并将 C++ class 指针作为 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;
    }
  }
}

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


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

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

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

还有其他示例:搜索 CppHostCLR