Вызов конструктора в custom. NET Core Host - PullRequest
0 голосов
/ 16 июня 2020

Я пытаюсь написать хост. NET Core, используя coreclr.h. Для этого я пытаюсь создать указатели функций на код c#. Я могу вызывать методы stati c с моего хоста, но вызов методов, которые напрямую зависят от объекта, не могут быть вызваны, в идеале я хотел бы иметь возможность вызывать конструктор и все нестандартные c методы из C ++ без изменения C#. Я могу вызвать Multiply5 и Main в порядке, но при вызове конструктора Program или Add возникает ошибка segfault, есть ли способ исправить это? Это система Linux, поэтому C ++ / CLI не подходит.

C ++

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "coreclrhost.h"
#include <iostream>
#define MANAGED_ASSEMBLY "TestConsole.dll"


#include <dirent.h>
#include <dlfcn.h>
#include <limits.h>
#define FS_SEPARATOR "/"
#define PATH_DELIMITER ":"
#define MAX_PATH PATH_MAX

#define CORECLR_FILE_NAME "libcoreclr.so"


// Function pointer types for the managed call and callback
typedef int (*report_callback_ptr)(int progress);
typedef char* (*doWork_ptr)(const char* jobName, int iterations, int dataSize, double* data, report_callback_ptr callbackFunction);
typedef int (*Multiply5_ptr)(const int i);
typedef (*Constructor_ptr)(int i1, int i2);
typedef int (*ReturnInt_ptr)();
void BuildTpaList(const char* directory, const char* extension, std::string& tpaList);

int main(int argc, char* argv[])
{
    // Get the current executable's directory
    // This sample assumes that both CoreCLR and the
    // managed assembly to be loaded are next to this host
    // so we need to get the current path in order to locate those.
    char runtimePath[MAX_PATH];
#if WINDOWS
    GetFullPathNameA(argv[0], MAX_PATH, runtimePath, NULL);
#elif LINUX
    realpath(argv[0], runtimePath);
#endif
    char *last_slash = strrchr(runtimePath, FS_SEPARATOR[0]);
    if (last_slash != NULL)
        *last_slash = 0;

    // Construct the CoreCLR path
    // For this sample, we know CoreCLR's path. For other hosts,
    // it may be necessary to probe for coreclr.dll/libcoreclr.so
    std::string coreClrPath(runtimePath);
    coreClrPath.append(FS_SEPARATOR);
    coreClrPath.append(CORECLR_FILE_NAME);

    // Construct the managed library path
    std::string managedLibraryPath(runtimePath);
    managedLibraryPath.append(FS_SEPARATOR);
    managedLibraryPath.append(MANAGED_ASSEMBLY);
    //
    // STEP 1: Load CoreCLR (coreclr.dll/libcoreclr.so)
    //
#if WINDOWS
    // <Snippet1>
    HMODULE coreClr = LoadLibraryExA(coreClrPath.c_str(), NULL, 0);
    // </Snippet1>
#elif LINUX
    void *coreClr = dlopen(coreClrPath.c_str(), RTLD_NOW | RTLD_LOCAL);
#endif
    if (coreClr == NULL)
    {
        printf("ERROR: Failed to load CoreCLR from %s\n", coreClrPath.c_str());
        return -1;
    }
    else
    {
        printf("Loaded CoreCLR from %s\n", coreClrPath.c_str());
    }

    //
    // STEP 2: Get CoreCLR hosting functions
    //
#if WINDOWS
    // <Snippet2>
    coreclr_initialize_ptr initializeCoreClr = (coreclr_initialize_ptr)GetProcAddress(coreClr, "coreclr_initialize");
    coreclr_create_delegate_ptr createManagedDelegate = (coreclr_create_delegate_ptr)GetProcAddress(coreClr, "coreclr_create_delegate");
    coreclr_shutdown_ptr shutdownCoreClr = (coreclr_shutdown_ptr)GetProcAddress(coreClr, "coreclr_shutdown");
    // </Snippet2>
#elif LINUX
    coreclr_initialize_ptr initializeCoreClr = (coreclr_initialize_ptr)dlsym(coreClr, "coreclr_initialize");
    coreclr_create_delegate_ptr createManagedDelegate = (coreclr_create_delegate_ptr)dlsym(coreClr, "coreclr_create_delegate");
    coreclr_shutdown_ptr shutdownCoreClr = (coreclr_shutdown_ptr)dlsym(coreClr, "coreclr_shutdown");
#endif

    if (initializeCoreClr == NULL)
    {
        printf("coreclr_initialize not found");
        return -1;
    }

    if (createManagedDelegate == NULL)
    {
        printf("coreclr_create_delegate not found");
        return -1;
    }

    if (shutdownCoreClr == NULL)
    {
        printf("coreclr_shutdown not found");
        return -1;
    }

    //
    // STEP 3: Construct properties used when starting the runtime
    //

    // Construct the trusted platform assemblies (TPA) list
    // This is the list of assemblies that .NET Core can load as
    // trusted system assemblies.
    // For this host (as with most), assemblies next to CoreCLR will
    // be included in the TPA list
    std::string tpaList;
    BuildTpaList(runtimePath, ".dll", tpaList);
    tpaList.append(managedLibraryPath);
    tpaList.append(":");
    // <Snippet3>
    // Define CoreCLR properties
    // Other properties related to assembly loading are common here,
    // but for this simple sample, TRUSTED_PLATFORM_ASSEMBLIES is all
    // that is needed. Check hosting documentation for other common properties.
    const char* propertyKeys[] = {
        "TRUSTED_PLATFORM_ASSEMBLIES"      // Trusted assemblies
    };

    const char* propertyValues[] = {
        tpaList.c_str()
    };

    // </Snippet3>

    //
    // STEP 4: Start the CoreCLR runtime
    //

    // <Snippet4>
    void* hostHandle;
    unsigned int domainId;

    // This function both starts the .NET Core runtime and creates
    // the default (and only) AppDomain
    int hr = initializeCoreClr(
                    runtimePath,        // App base path
                    "SampleHost",       // AppDomain friendly name
                    sizeof(propertyKeys) / sizeof(char*),   // Property count
                    propertyKeys,       // Property names
                    propertyValues,     // Property values
                    &hostHandle,        // Host handle
                    &domainId);         // AppDomain ID
    // </Snippet4>

    if (hr >= 0)
    {
        printf("CoreCLR started\n");
    }
    else
    {
        printf("coreclr_initialize failed - status: 0x%08x\n", hr);
        return -1;
    }

    //
    // STEP 5: Create delegate to managed code and invoke it
    //

    // <Snippet5>
    Multiply5_ptr managedDelegate;
    // The assembly name passed in the third parameter is a managed assembly name
    // as described at https://docs.microsoft.com/dotnet/framework/app-domains/assembly-names
    hr = createManagedDelegate(
            hostHandle,
            domainId,
            "TestConsole, Version=1.0.0.0",
            "TestConsole.Program",
            "Multiply5",
            (void**)&managedDelegate);

    // </Snippet5>

    if (hr >= 0)
    {
        printf("Managed delegate created\n");
    }
    else
    {
        printf("coreclr_create_delegate failed - status: 0x%08x\n", hr);
        return -1;
    }


    int i = 20;

    // Invoke the managed delegate and write the returned intS to the console
    //char* ret = managedDelegate("Test job", 1, sizeof(int), i, ReportProgressCallback);
    int ret = managedDelegate(i);
    printf("Managed code returned: %d\n", ret);

    Constructor_ptr programDelegate;

    hr = createManagedDelegate(hostHandle,
            domainId,
            "TestConsole, Version=1.0.0.0",
            "TestConsole.Program",
            "Program",
            (void**)&programDelegate);
    int i1 = i;
    int i2 = ret;
    programDelegate(i1,i2);//Will seg fault here

    ReturnInt_ptr addDelegate;
    hr = createManagedDelegate(hostHandle,
            domainId,
            "TestConsole, Version=1.0.0.0",
            "TestConsole.Program",
            "Add",
            (void**)&addDelegate);
    i = addDelegate(); //Also triggers a seg fault.
    printf("Managed code returned: %d\n", i);
    // Strings returned to native code must be freed by the native code
#if WINDOWS
    CoTaskMemFree(ret);
#elif LINUX
   // free(ret);
#endif

    //
    // STEP 6: Shutdown CoreCLR
    //

    // <Snippet6>
    hr = shutdownCoreClr(hostHandle, domainId);
    // </Snippet6>

    if (hr >= 0)
    {
        printf("CoreCLR successfully shutdown\n");
    }
    else
    {
        printf("coreclr_shutdown failed - status: 0x%08x\n", hr);
    }

    return 0;
}

#if WINDOWS
// Win32 directory search for .dll files
// <Snippet7>
void BuildTpaList(const char* directory, const char* extension, std::string& tpaList)
{
    // This will add all files with a .dll extension to the TPA list.
    // This will include unmanaged assemblies (coreclr.dll, for example) that don't
    // belong on the TPA list. In a real host, only managed assemblies that the host
    // expects to load should be included. Having extra unmanaged assemblies doesn't
    // cause anything to fail, though, so this function just enumerates all dll's in
    // order to keep this sample concise.
    std::string searchPath(directory);
    searchPath.append(FS_SEPARATOR);
    searchPath.append("*");
    searchPath.append(extension);

    WIN32_FIND_DATAA findData;
    HANDLE fileHandle = FindFirstFileA(searchPath.c_str(), &findData);

    if (fileHandle != INVALID_HANDLE_VALUE)
    {
        do
        {
            // Append the assembly to the list
            tpaList.append(directory);
            tpaList.append(FS_SEPARATOR);
            tpaList.append(findData.cFileName);
            tpaList.append(PATH_DELIMITER);

            // Note that the CLR does not guarantee which assembly will be loaded if an assembly
            // is in the TPA list multiple times (perhaps from different paths or perhaps with different NI/NI.dll
            // extensions. Therefore, a real host should probably add items to the list in priority order and only
            // add a file if it's not already present on the list.
            //
            // For this simple sample, though, and because we're only loading TPA assemblies from a single path,
            // and have no native images, we can ignore that complication.
        }
        while (FindNextFileA(fileHandle, &findData));
        FindClose(fileHandle);
    }
}
// </Snippet7>
#elif LINUX
// POSIX directory search for .dll files
void BuildTpaList(const char* directory, const char* extension, std::string& tpaList)
{
    DIR* dir = opendir(directory);
    struct dirent* entry;
    int extLength = strlen(extension);

    while ((entry = readdir(dir)) != NULL)
    {
        // This simple sample doesn't check for symlinks
        std::string filename(entry->d_name);

        // Check if the file has the right extension
        int extPos = filename.length() - extLength;
        if (extPos <= 0 || filename.compare(extPos, extLength, extension) != 0)
        {
            continue;
        }

        // Append the assembly to the list
        tpaList.append(directory);
        tpaList.append(FS_SEPARATOR);
        tpaList.append(filename);
        tpaList.append(PATH_DELIMITER);

        // Note that the CLR does not guarantee which assembly will be loaded if an assembly
        // is in the TPA list multiple times (perhaps from different paths or perhaps with different NI/NI.dll
        // extensions. Therefore, a real host should probably add items to the list in priority order and only
        // add a file if it's not already present on the list.
        //
        // For this simple sample, though, and because we're only loading TPA assemblies from a single path,
        // and have no native images, we can ignore that complication.
    }
}
#endif

C#

namespace TestConsole
{
    public class Program
    {

        IntTest i;

        Program(int i1, int i2){
            i = new IntTest(i1,i2);
        }

        public static void Main()
        {
            Program p = new Program(23,12);
            Console.WriteLine(p.Add());
        }


        // This test method doesn't actually do anything, it just takes some input parameters,
        // waits (in a loop) for a bit, invoking the callback function periodically, and
        // then returns a string version of the double[] passed in.
        //[return: MarshalAs(UnmanagedType.I4)]
        public static int Return5(){
            return 5;
        }

        public int Add(){
            return i.Add();
        }

        private static int Multiply5(int i){
                return 5*i;
        }
    }
}

IntTest - внешний библиотека.

1 Ответ

0 голосов
/ 19 июня 2020
• 1000
...