Skip to content

Instantly share code, notes, and snippets.

@zwcloud
Created November 21, 2016 08:38
Show Gist options
  • Star 29 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save zwcloud/b342d264176ee2143aca970a9933e5cc to your computer and use it in GitHub Desktop.
Save zwcloud/b342d264176ee2143aca970a9933e5cc to your computer and use it in GitHub Desktop.
An example on embedding Mono runtime in C/C++.
using System;
public class Dog
{
static public void Type()
{
Console.WriteLine("a Dog!");
}
public void Bark()
{
Console.WriteLine("bark!");
}
public void Bark(int times)
{
for (var i = 0; i < times; ++i )
Console.WriteLine("bark!");
}
}
#include <windows.h>
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/debug-helpers.h>
#include <cstdlib>
#include <string>
#include <iostream>
#pragma comment(lib, "mono-2.0.lib")
int main(int argc, char* argv[])
{
#pragma region Load and compile the script
std::string scriptPath(R"(D:\Mono\Dog.cs)");
std::string command = "mcs " + scriptPath + " -target:library";
//Compile the script
system(command.c_str());
#pragma endregion
#pragma region Init mono runtime
mono_set_dirs("C:\\Program Files (x86)\\Mono\\lib",
"C:\\Program Files (x86)\\Mono\\etc");
//Init a domain
MonoDomain *domain;
domain = mono_jit_init("MonoScriptTry");
if (!domain)
{
std::cout << "mono_jit_init failed" << std::endl;
system("pause");
return 1;
}
//Open a assembly in the domain
MonoAssembly *assembly;
char* assemblyPath = "D:\\Mono\\Dog.dll";
assembly = mono_domain_assembly_open(domain, assemblyPath);
if (!assembly)
{
std::cout << "mono_domain_assembly_open failed" << std::endl;
system("pause");
return 1;
}
//Get a image from the assembly
MonoImage* image;
image = mono_assembly_get_image(assembly);
if (!image)
{
std::cout << "mono_assembly_get_image failed" << std::endl;
system("pause");
return 1;
}
#pragma endregion
#pragma region Run a static method
{
//Build a method description object
MonoMethodDesc* TypeMethodDesc;
char* TypeMethodDescStr = "Dog:Type()";
TypeMethodDesc = mono_method_desc_new(TypeMethodDescStr, NULL);
if (!TypeMethodDesc)
{
std::cout << "mono_method_desc_new failed" << std::endl;
system("pause");
return 1;
}
//Search the method in the image
MonoMethod* method;
method = mono_method_desc_search_in_image(TypeMethodDesc, image);
if (!method)
{
std::cout << "mono_method_desc_search_in_image failed" << std::endl;
system("pause");
return 1;
}
//run the method
std::cout << "Running the static method: " << TypeMethodDescStr << std::endl;
mono_runtime_invoke(method, nullptr, nullptr, nullptr);
}
#pragma endregion
#pragma region Run a normal method
{
//Get the class
MonoClass* dogclass;
dogclass = mono_class_from_name(image, "", "Dog");
if (!dogclass)
{
std::cout << "mono_class_from_name failed" << std::endl;
system("pause");
return 1;
}
//Create a instance of the class
MonoObject* dogA;
dogA = mono_object_new(domain, dogclass);
if (!dogclass)
{
std::cout << "mono_object_new failed" << std::endl;
system("pause");
return 1;
}
//Call its default constructor
mono_runtime_object_init(dogA);
//Build a method description object
MonoObject* result;
MonoMethodDesc* BarkMethodDesc;
char* BarkMethodDescStr = "Dog:Bark(int)";
BarkMethodDesc = mono_method_desc_new(BarkMethodDescStr, NULL);
if (!BarkMethodDesc)
{
std::cout << "mono_method_desc_new failed" << std::endl;
system("pause");
return 1;
}
//Search the method in the image
MonoMethod* method;
method = mono_method_desc_search_in_image(BarkMethodDesc, image);
if (!method)
{
std::cout << "mono_method_desc_search_in_image failed" << std::endl;
system("pause");
return 1;
}
//Set the arguments for the method
void* args[1];
int barkTimes = 3;
args[0] = &barkTimes;
//Run the method
std::cout << "Running the method: " << BarkMethodDescStr << std::endl;
mono_runtime_invoke(method, dogA, args, nullptr);
}
#pragma endregion
system("pause");
return 0;
}
Copy link

ghost commented Oct 18, 2017

Hello dear great example.

I replace from old version #pragma comment(lib, "mono-2.0.lib")

to new version:
#pragma comment(lib, "mono-2.0-boehm.lib") // replaced from mono-2.0.lib
#pragma comment(lib, "mono-2.0-sgen.lib") // It is new with GC code library GC from Gnu Compilication

But I got error if I have parsing system...

D:\Mono\Dog.cs(15,21): error CS0589: Internal compiler error during parsingSystem.MissingMethodException: Method not found: 'Void System.Array.Reverse(!!0[])'.
   at Mono.CSharp.Tokenizer.Position..ctor(Tokenizer t)
   at Mono.CSharp.Tokenizer.TokenizeLessThan()
   at Mono.CSharp.Tokenizer.xtoken()
   at Mono.CSharp.Tokenizer.token()
   at Mono.CSharp.CSharpParser.yyparse(yyInput yyLex)
   at Mono.CSharp.CSharpParser.parse()
Compilation failed: 1 error(s), 0 warnings
Running the static method: Dog:Type()
a Dog!
Running the method: Dog:Bark(int)
bark!
bark!
bark!
Press any key to continue . . .

How do I fix it? Thanks I am really excited to own embedding mono application without mono runtime.

@zwcloud
Copy link
Author

zwcloud commented Apr 24, 2018

@sourceskyboxer I just saw your comment. It seems your code doesn't include the default assemblies such as System.Runtime.dll. I'm not sure if the method System.Array.Reverse is defined in that assembly.

@ArionTT
Copy link

ArionTT commented Jun 11, 2018

Hi, I use mono to embed the CSharp program to my C++ program. I want to call the method to return a array.
MonoObject* obj=mono_runtime_invoke(Method,MyClass,NULL,NULL);
MonoArray*arr=(MonoArray*)obj;
And now, I don't know how to cast MonoArray to my local var for example, float[].
For MonoObject* type, I just call mono_object_unbox() method is fine.

Do you know how to cast it?

@zwcloud
Copy link
Author

zwcloud commented Oct 31, 2018

@ArionTT Just saw your post...
Have you solved your problem?

@kkolyan
Copy link

kkolyan commented Mar 25, 2021

If you don't mind, I use code from this gist here https://github.com/kkolyan/embedmono

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment