目次

Monoの組み込み

Monoの言語(C#、Boo、etc.)をスクリプティングとして使う場合とかに使える、C++の小さいサンプル。

このサンプルでは「C++→スクリプト」と「スクリプト→C++」の2方向の呼び出しを試している。

「C++→スクリプト」はMonoのAPI (mono_runtime_invokeとか) をつかってがんばる。「スクリプト→C++」はP/Invokeを使えばできる。

動作環境

確認環境

ビルド方法

$ booc test_boo.boo
$ dmcs test_cs.cs
$ g++ -export-dynamic -g monotest.cpp -o monotest `pkg-config --cflags --libs mono-2`

使用方法

$ ./monotest lib <テスト用アセンブリ>
$ ./monotest app <.NETアプリケーション>

ソースコード

ホストプログラム

monotest.cpp
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/mono-config.h>
 
#include <string>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
 
#ifdef _MSC_VER
#	define EXPORT_FUNC  extern __declspec(dllexport)
#else
#	include <dlfcn.h>
#	define EXPORT_FUNC	
#endif	
 
using namespace std;
 
extern "C" {
EXPORT_FUNC void PrintFunc(int val);
}
 
void error(const string &msg = "")
{
	cerr << "Error:" << msg << endl;
	abort();
}
 
int main(int argc, char* argv[])
{
    int retval;
#ifndef _MSC_VER
	// Export Check
	void *ThisModule = dlopen(NULL, RTLD_LAZY);
	cout << "Module Handle:" << ThisModule << endl;
	void *pFunc = dlsym(ThisModule, "PrintFunc");
	cout << "Function Handle:" << pFunc << endl;
	if(!pFunc)
		error("No symbol: PrintFunc");
	// mono_set_dirs("./monolib","./monoetc");
#else
	mono_set_dirs(".\\monolib",".\\monoetc");
#endif	
	MonoDomain *domain;
 
	if (argc < 3){
		fprintf (stderr, "Please provide an assembly to load\n");
		return 1;
	}
	string cmd = argv[1];
	string file = argv[2];
 
    mono_config_parse(NULL);
    domain = mono_jit_init("monotest");
    if(cmd == "lib")
    {
        MonoAssembly *assembly = mono_domain_assembly_open (domain, file.c_str());
        if (!assembly)
            error("No such assembly");
 
        PrintFunc(0);
 
        MonoImage *image = mono_assembly_get_image(assembly);
        MonoClass *klass = mono_class_from_name(image, "TestNamespace", "TestClass");
        MonoMethodDesc *desc = mono_method_desc_new(":TestStaticMethod(int)", false);
        MonoMethod *static_method = mono_method_desc_search_in_class (desc, klass);
 
        void *args[1];
        int val1 = 1234;
        args[0] = &val1;
        mono_runtime_invoke (static_method, NULL, args, NULL);
    }
    else
    {
        MonoAssembly *assembly = mono_domain_assembly_open (domain, file.c_str());
        retval = mono_jit_exec (domain, assembly, argc - 1, argv + 1);
    }
    mono_jit_cleanup(domain);
	return retval;
}
 
void PrintFunc(int val)
{
	cout << "In PrintFunc :" << val << endl;
}

テスト用アセンブリのソース

test_boo.boo
namespace TestNamespace
 
import System.Runtime.InteropServices
 
[DllImport("__Internal", EntryPoint: "PrintFunc")]
def PrintFunc(val as int):
	pass
 
class TestClass:
	static def TestStaticMethod(val1 as int):
		print "In TestClass: ", val1
		PrintFunc(val1 * 2)
		return
test_cs.cs
using System;
using System.Runtime.InteropServices;
 
namespace TestNamespace{
class TestClass
{
	[DllImport("__Internal")]
	public static extern void PrintFunc(int v);
 
	static void TestStaticMethod(int val1)
	{
		Console.WriteLine("In TestClass: ");
		Console.WriteLine(val1);
		PrintFunc(val1 * 2);
		return;
	}
}
}