1

I need to pass an array from C++ to C# using mono. But I can't get mono_array_set() to compile. So how can I pass an array from C++ to C#?

I've tried mono_runtime_invoke() which compiles but gives a runtime error.

mcs /nologo /warn:4 /debug:pdbonly /o /nowarn:3003 /platform:x64 /out:array.dll /target:library array.cs
g++ array.cpp -g3 `pkg-config --cflags --libs mono-2` -o array
<snip> 
array.cpp:32:5: note: in expansion of macro ‘mono_array_set’

// array.cpp
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/debug-helpers.h>

int main(int argc, char* argv[]) {
    MonoDomain* domain = mono_jit_init("./array.dll");;
    MonoAssembly* assembly = mono_domain_assembly_open(domain, "./array.dll");
    MonoImage* image = mono_assembly_get_image(assembly);

    MonoClass* containsClass = mono_class_from_name(image, "IntArray", "ContainsAnInt");
    MonoMethodDesc* containsDesc = mono_method_desc_new("IntArray.ContainsAnInt:.ctor(int)", false);
    MonoMethod* containsCtor = mono_method_desc_search_in_class(containsDesc, containsClass);
    MonoObject* containsObject = mono_object_new(domain, containsClass);

    void* args[1];
    int value = 7;
    args[0] = &value;

    MonoObject* exception = NULL;
    mono_runtime_invoke(containsCtor, containsObject, args, &exception);

    MonoClass* unpackageClass = mono_class_from_name(image, "IntArray", "Unpackage");

    args[0] = containsObject;
    MonoMethodDesc* returnIntDesc = mono_method_desc_new("IntArray.Unpackage:ReturnInt(IntArray.ContainsAnInt)", true);
    MonoMethod* returnIntMethod = mono_method_desc_search_in_class(returnIntDesc, unpackageClass);
    mono_runtime_invoke(returnIntMethod, NULL, args, &exception); // <--- as expected, outputs "In ReturnInt: 7"

    MonoArray* theArray = mono_array_new(domain, containsClass, 1);
    //// Following will not compile
    mono_array_set(theArray, MonoClass*, 0, containsObject);
    ////
    MonoMethodDesc* returnElementDesc = mono_method_desc_new("IntArray.Unpackage:ReturnElement(IntArray.ContainsAnInt[])", true);
    MonoMethod* returnElementMethod = mono_method_desc_search_in_class(returnElementDesc, unpackageClass);
    mono_runtime_invoke_array(returnElementMethod, NULL, theArray, &exception); // <--- should output "In ReturnElement: 7"

    mono_jit_cleanup(domain);
}

// array.cs
using System;
using System.IO;

namespace IntArray {
    public class ContainsAnInt {
       public ContainsAnInt(int i) { IntValue = i;  }
       public int IntValue { get; set; }
    }
    public class Unpackage {
        public static int ReturnInt(ContainsAnInt n) {
            Console.WriteLine("In ReturnInt: " + n.IntValue); 
            return n.IntValue;
        }
        public static int ReturnElement(ContainsAnInt[] n) {
            Console.WriteLine("In ReturnElement: " + n[0].IntValue); 
            return n[0].IntValue;
        }
    }
}
0

2 Answers 2

2

This works:

MonoArray* theArray = mono_array_new(domain, containsClass, 1);
mono_array_set(theArray, MonoObject*, 0, containsObject);
args[0] = theArray;
mono_runtime_invoke(returnElementMethod, NULL, args, &exception); // <--- as expected, outputs "In ReturnElement: 7"
Sign up to request clarification or add additional context in comments.

Comments

1

This also works because I was able to define a C struct with the exact same layout as System.Drawing.PointF . Still unanswered is what if I needed to populate an array of C# classes from C++?

MonoArray* arrayPtF = mono_array_new(domain, ptFClass, 2);
struct cpoint {
    float x, y;
} mycpoint[] = { { 42, 1701 }, { 1701, 42 } };
mono_array_set(arrayPtF, cpoint, 0, mycpoint[0]);
mono_array_set(arrayPtF, cpoint, 1, mycpoint[1]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.