4

I'm trying to load mono assemblies from memory. My question has two parts, first: when I use mono_image_open_from_data and mono_assembly_load_from combination the assembly dependencies are not loaded. If I load assembly dependencies manually with same methods it seems that they are not added to application domain. So it does not work.

So I want to know if there is any way to load these assemblies from memory.

Second: If it is possible to load assemblies from memory, is it possible to load mscorlib.dll from memory too? The mono_jit_init tries to load it from library path and if it does not exist in the path mono will fail to initialize. Is there any way to load it from memory?

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
KooKoo
  • 451
  • 3
  • 20

1 Answers1

4

If someone still looks for this in 2021:

C# Module :

using System;

namespace dotNetLib
{
    public class API
    {
        static public void DoSomething()
        {
            Console.WriteLine("Hello From C#!");
        }
    }
}

C++ Mono :

#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>

#include "module.h" // unsigned char asmData[SIZE] = { 0x4D, 0x5A, 0x90, 0x00, 0x03...

MonoDomain* domain;
MonoAssembly* assembly;

using namespace std;

#define log(fmt,...) printf(fmt "\n",__VA_ARGS__);
#define error(code) {log("exited with error %d",code);getchar();return code;}

int LoadFromFile();
int LoadFromMemory();

#define LOAD_FROM_MEMORY true

int main() 
{
    if (LOAD_FROM_MEMORY)
    {
        LoadFromMemory();
    }
    else 
    {
        LoadFromFile();
    }
}

int LoadFromMemory()
{
    log("Initializing Domain...");
    mono_set_dirs(".\\lib", "");
    domain = mono_jit_init_version("myapp", "v4.0.30319");
    if (!domain) error(-2);
    log("Loading Image...");
    MonoImageOpenStatus status;
    MonoImage* image = mono_image_open_from_data((char*)asmData, sizeof asmData, false, &status);
    if (!image) error(-3);
    if (status != MONO_IMAGE_OK) error(-4);
    log("Loading Module...");
    assembly = mono_assembly_load_from(image, "", &status);
    if (!assembly) error(-5);
    if (status != MONO_IMAGE_OK) error(-6);
    log("Getting Class...");
    MonoClass* getClass = mono_class_from_name(image, "dotNetLib", "API");
    if (!getClass) error(-7);
    log("Getting Method...");
    MonoMethod* method = mono_class_get_method_from_name(getClass, "DoSomething", 0);
    if (!method) error(-8);
    log("Calling Method...");
    void* params[1] = { NULL };
    MonoObject* returnVal = mono_runtime_invoke(method, NULL, params, NULL);
    getchar();
    log("Cleaning Up...");
    mono_jit_cleanup(domain);
}

int LoadFromFile() 
{
    log("Initializing Domain...");
    mono_set_dirs(".\\lib", "");
    domain = mono_jit_init_version("myapp", "v4.0.30319");
    if (!domain) error(6);
    log("Creating Module...");
    assembly = mono_domain_assembly_open(domain, "dotNetLib.dll");
    if (!assembly) error(7);
    MonoImage* image = mono_assembly_get_image(assembly);
    if (!image) error(8);
    log("Getting Class...");
    MonoClass* getClass = mono_class_from_name(image, "dotNetLib", "API");
    if (!getClass) error(9);
    log("Getting Method...");
    MonoMethod* method = mono_class_get_method_from_name(getClass, "DoSomething", 0);
    if (!method) error(10);
    log("Calling Method...");
    void* params[1] = { NULL };
    MonoObject* returnVal = mono_runtime_invoke(method, NULL, params, NULL);
    getchar();
    log("Cleaning Up...");
    mono_jit_cleanup(domain);
}
  • If you have dependencies issues, use Fody/Costura
  • If you want to load mscorlib.dll from memory you need to do some changes in mono source code or use a virtual file system like BoxedAppSDK or Turbo.Net or Enigma Virtual Box (free)

To embed and run mscorlib.dll from memory you need to store it as a byte array and use mono_register_bundled_assemblies() to register them.

C++ Mono :

static MonoBundledAssembly _mscorlib = { "mscorlib.dll", mscorlib, sizeof mscorlib };

int LoadFromMemory()
{
    MonoBundledAssembly* bundled[1];
    bundled[0] = &_mscorlib;
    mono_register_bundled_assemblies((const MonoBundledAssembly**)bundled);
    log("Initializing Domain...");
    ...

That's it!