передача управляемых экземпляров C# между C# и C++, когда в собственном процессе размещается среда выполнения .NET Core.

Я создаю прототип, используя пример HostWitHostFxr, который позволяет собственному процессу размещать .NET Core с использованием библиотек nethost и hostfxr. https://github.com/dotnet/samples/tree/master/core/hosting/HostWithHostFxr

Я пытаюсь вернуть экземпляр управляемого объекта с С# на С++. Затем C++ вызывает другой метод C#, чтобы сделать что-то с управляемым объектом и освободить его.

Прямо сейчас я терплю неудачу на 2-м шаге с: Необработанное исключение. System.NullReferenceException: ссылка на объект не указывает на экземпляр объекта.

Из исследования, которое я провел, я понял, что для возврата ссылки на управляемый объект С# на С++ мне нужно будет использовать 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()");

Чего мне не хватает, чтобы заставить это работать?


person Robert Dugal    schedule 03.06.2020    source источник


Ответы (1)


ДОХ! Проблема с моим кодом в getFoobar(). Вместо:

IntPtr ptr = handle.AddrOfPinnedObject();

мне нужно:

IntPtr ptr = GCHandle.ToIntPtr(handle);

Кажется, это работает.

person Robert Dugal    schedule 03.06.2020