StudioCherno / Coral

Coral is a C++/C# wrapper around the .NET CoreCLR library, the purpose of Coral is to provide a native interface similar to Mono, but in a more modern style, and using .NET Core instead of .NET Framework
MIT License
210 stars 26 forks source link

Invalid ID Error. #19

Closed kaitabuchi314 closed 2 months ago

kaitabuchi314 commented 2 months ago

I am trying to make C# bindings for C++ for a game engine. This is the ScriptEngine.cpp file:

#include "ScriptEngine.h"

namespace Square
{
    Assembly* LoadAssembly(int argc, char** argv, const std::string& assemblyDLL)
    {
        auto exeDir = std::filesystem::path(argv[0]).parent_path();
        auto coralDir = exeDir.string();

        Coral::HostSettings settings =
        {
            .CoralDirectory = coralDir,
            .ExceptionCallback = ExceptionCallback
        };
        Coral::HostInstance hostInstance;
        hostInstance.Initialize(settings);

        auto loadContext = hostInstance.CreateAssemblyLoadContext("ExampleContext");

        auto assemblyPath = std::string(exeDir.string()) + std::string("/") + assemblyDLL;
        auto& assembly = loadContext.LoadAssembly(assemblyPath);

        assembly.AddInternalCall("SquareEngine.Entity", "LogInternal", reinterpret_cast<void*>(&Log));
        assembly.AddInternalCall("SquareEngine.Entity", "RandVectorInternal", reinterpret_cast<void*>(&RandVector));

        assembly.UploadInternalCalls();

        Assembly a = Assembly { assembly };

        return &a;
    }

    Script* LoadScript(Assembly* assembly, const std::string& name)
    {
        Coral::Type& type = assembly->coralAssembly.GetType(name);

        Script script = Script { name, type };

        return &script;
    }

    InstantiatedScript* CreateScript(Script* script)
    {
        Coral::ManagedObject instance = script->type.CreateInstance();
        InstantiatedScript sc = { script->name, &instance };
        return &sc;
    }

    void RunFunction(InstantiatedScript* script, const std::string& func)
    {
        script->obj->InvokeMethod(func);
    }
}

Header:

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <filesystem>
#include <chrono>
#include <functional>
#include <ranges>

#include <Coral/HostInstance.hpp>
#include <Coral/GC.hpp>
#include <Coral/Array.hpp>
#include <Coral/Attribute.hpp>

#include "Glue.h"

namespace Square
{
    struct Assembly
    {
        Coral::ManagedAssembly& coralAssembly;
    };

    struct Script
    {
        std::string_view name;
        Coral::Type& type;
    };

    struct InstantiatedScript
    {
        std::string_view name;
        Coral::ManagedObject* obj;
    };

    inline void ExceptionCallback(std::string_view InMessage) { std::cout << "Unhandled native exception: " << InMessage << std::endl; };

    Assembly* LoadAssembly(int argc, char** argv, const std::string& assemblyDLL);

    Script* LoadScript(Assembly* assembly, const std::string& name);

    InstantiatedScript* CreateScript(Script* script);

    void RunFunction(InstantiatedScript* script, const std::string& func);
}

I get the following error:

System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

Call Stack: image

Console:

[Coral](Info): Loading assembly 'D:\dev\SquareEngine\scripting\Coral\Build\Release/Example.Managed.dll'
[Coral](Error): Failed to find type with id '1928776192'.
Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at Coral.Managed.ManagedObject.InvokeMethod(IntPtr, Coral.Managed.Interop.NativeString, IntPtr, Coral.Managed.ManagedType*, Int32)

Main.cpp:

#include "ScriptEngine.h"

int main(int argc, char** argv)
{
    Square::Assembly* mainAssembly = Square::LoadAssembly(argc, argv, "Example.Managed.dll");
    Square::Script* nonInstantiatedPlayerScript = Square::LoadScript(mainAssembly, "Example.PlayerScript");
    Square::InstantiatedScript* playerScript = Square::CreateScript(nonInstantiatedPlayerScript);

    Square::RunFunction(playerScript, "OnStart");
    Square::RunFunction(playerScript, "OnUpdate");
    Square::RunFunction(playerScript, "OnUpdate");
    Square::RunFunction(playerScript, "OnUpdate");

    return 0;
}