c# - 当 native 进程托管 .NET Core 运行时时,在 C# 和 C++ 之间传递 C# 托管实例

标签 c# c++ coreclr clr-hosting

我正在使用 HostWitHostFxr 示例进行原型(prototype)设计,该示例允许 native 进程使用 nethost 和 hostfxr 库托管 .NET Core。
https://github.com/dotnet/samples/tree/master/core/hosting/HostWithHostFxr

我正在尝试将托管对象的实例从 C# 返回到 C++。
然后 C++ 调用另一个 C# 方法对托管对象执行某些操作并释放它。

现在我在第二步失败了:
未处理的异常。 System.NullReferenceException:对象引用未设置为对象的实例。

根据我所做的研究,我的理解是,要返回对 C++ 的托管 C# 对象引用,我需要使用 GCHandle.Alloc() 和 GCHandleType.Pinned 来固定对象。

我修改了 C# 示例 Lib.cs 以添加一个新的 Foobar 类:

    // prototype
    [StructLayout(LayoutKind.Sequential)]
    public class Foobar
    {
        public Foobar()
        {
            Console.WriteLine("Foobar constr");
        }

        ~Foobar()
        {
            Console.WriteLine("Foobar destr");
        }

        public bool do_something()
        {
            Console.WriteLine("Foobar.do_something()");
            return true;
        }
    }

我添加了一个返回 Foobar 实例的方法:
        // prototype: from static method return a Foobar instance
        public delegate IntPtr getFoobarDelegate();
        public static IntPtr getFoobar() {
            Console.WriteLine("getFoobar()");

            Foobar obj = new Foobar();
            GCHandle handle = GCHandle.Alloc(obj, GCHandleType.Pinned);
            IntPtr ptr = handle.AddrOfPinnedObject();
            Console.WriteLine($"getFoobar() return {ptr}");
            return ptr;
        }

我添加了一个方法来处理 Foobar 的实例并释放它:
        // prototype: from static method use and destroy a Foobar instance
        public delegate bool freeFoobarDelegate(IntPtr foo);
        public static bool freeFoobar(IntPtr foo) {
            Console.WriteLine($"freeFoobar() foo {foo}");
            if (foo == IntPtr.Zero) return false;
            GCHandle gch = GCHandle.FromIntPtr(foo);

            Foobar a = (gch.Target as Foobar);
            a.do_something();
            gch.Free();
            foo = IntPtr.Zero;
            return true;
        }

在 C++ 端,我修改了 nativehost.cpp 以添加此代码以获取 Foobar 实例:
    // prototype: call C# getFoobar()
    typedef intptr_t (CORECLR_DELEGATE_CALLTYPE *getFoobar_fn)();
    getFoobar_fn getFoobar = nullptr;
    rc = load_assembly_and_get_function_pointer(
        dotnetlib_path.c_str(),
        dotnet_type,
        STR("getFoobar") /*method_name*/,
        STR("DotNetLib.Lib+getFoobarDelegate, DotNetLib") /*delegate_type_name*/,
        nullptr,
        (void**)&getFoobar);
    assert(rc == 0 && getFoobar != nullptr && "Failure: load_assembly_and_get_function_pointer()");
    intptr_t scorer = getFoobar();
    assert(scorer != 0 && "Failure: getFoobar()");


这与 Foobar 实例做一些事情:
    // prototype: call C# freeFoobar()
    typedef bool (CORECLR_DELEGATE_CALLTYPE *freeFoobar_fn)(intptr_t);
    freeFoobar_fn freeFoobar = nullptr;
    rc = load_assembly_and_get_function_pointer(
        dotnetlib_path.c_str(),
        dotnet_type,
        STR("freeFoobar") /*method_name*/,
        STR("DotNetLib.Lib+freeFoobarDelegate, DotNetLib") /*delegate_type_name*/,
        nullptr,
        (void**)&freeFoobar);
    assert(rc == 0 && freeFoobar != nullptr && "Failure: load_assembly_and_get_function_pointer()");
    bool ret = freeFoobar(scorer);
    assert(ret != 0 && "Failure: freeFoobar()");


为了让这个工作,我缺少什么?

最佳答案

哦!我在 getFoobar() 中的代码有问题。
代替:

IntPtr ptr = handle.AddrOfPinnedObject();

我需要:
IntPtr ptr = GCHandle.ToIntPtr(handle);

这似乎有效。

关于c# - 当 native 进程托管 .NET Core 运行时时,在 C# 和 C++ 之间传递 C# 托管实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62175022/

相关文章:

c# - 有没有办法用 NAudio 播放 AAC 流?

c# - .NET HashSet 的内部实现包含方法?

c# - 使用 C# 构建 Excel 文件

macos - 我们可以在 mac OS X 中创建 asp 5 应用程序而不使用 mono 吗?

c# - 在 Linux 上使用 CoreCLR 从 C++ 调用 C# 方法

C# JsonProperty 名称为 "formattable"

c++ - MPI程序的段错误

c++ - 为什么主函数无法识别另一个函数是否返回 float 类型的数字

C++ 运算符重载和继承

c# - (http) coreclr/dnxCore 中的 Web 请求提供程序?