[Mono-list] Combining Virtuoso and Mono

Paolo Molaro lupus@ximian.com
Thu, 1 Aug 2002 13:17:05 +0200


On 07/31/02 Tim Haynes wrote:
> We know that such a thing is not immediate on your roadmap and thus would
> be interested in considering donating results of our unmanaged interface
> related development work to the Mono project if we could get some technical
> support for our developers for getting started in this direction.

As Miguel points out a possibility is to write a wrapper that mimics the
ms hosting API, though their API is really orrible and I really want a
clean interface for embedding mono.

> Specifically, we would appreciate either a pointer to existing
> documentation or assistance with the following points:
> 
> - How do we register an instance handle in unmanaged memory for GC?

Currently we don't provide an API specifically for that.
You can use a MonoGHashTable (check the mono/utils/mono-hash.h):
it works just like a GHashTable but you can store objects in there
and they will be tracked by the GC if you store a pointer to the hash
table on the stack or in a static variable.
The alternative is to expose with a nice API the functionality provided
in metadata/gc.c that is already exposed to C# code (GCHandle): this way
you can not only ensure that an object that you store in unmanaged
memory is not collected, but you can also get weak references to it.

> - How do we call a method of an instance given the name and signature?

There are two functions to call a managed method:
MonoObject*
mono_runtime_invoke         (MonoMethod *method, void *obj, void **params,
                             MonoObject **exc);
and
MonoObject*
mono_runtime_invoke_array   (MonoMethod *method, void *obj, MonoArray *params,
                             MonoObject **exc);

obj is the 'this' pointer, it should be NULL for static methods, a
MonoObject* for object instances and a pointer to the value type for
value types.
The params array contains the arguments to the method with the same
convention: MonoObject* pointers for object instances and pointers to
the value type otherwise. The _invoke_array variant takes a C# object[]
as the params argument (MonoArray *params): in this case the value types
are boxed inside the respective reference representation.
From unmanaged code you'll usually use the mono_runtime_invoke()
variant. 
Note that this function doesn't handle virtual methods for you, it will
exec the exact method you pass: we still need to expose a function
to lookup the derived class implementation of a virtual method
(there are examples of this in the code, though).
You can pass NULL as the exc argument if you don't want to catch
exceptions, otherwise, *exc will be set to the exception thrown, if any.
if an exception is thrown, you can't use the MonoObject* result from the
function.
If the method returns a value type, it is boxed in an object reference.

We have plans for providing an additional method that returns an
unmanaged->managed thunk like this:

void* mono_method_get_unmanaged_thunk (MonoMethod *method);
You'll be able to store the returned pointer in a function pointer with
the proper signature and call that directly from C:

typedef gint32 (*GetHashCode) (MonoObject *obj);

GetHashCode func = mono_method_get_unmanaged_thunk (System_Object_GetHashCode_method);

gint32 hashvalue = func (myobject);

It may not be possible to manage exceptions in that case, though. I need
to think more about it.

To get a MonoMethod there are several ways.
You can get a MonoClass (the structure representing a type) using:

MonoClass *
mono_class_from_name (MonoImage *image, const char* name_space, const char *name);

and then loop in the returned class method array until you get the one
you're looking for. There are examples of such searches as static
functions in several C files in metadata/*.c: we need to expose one
through the API and remove the duplicates.

The other, simpler, way is to use the functions in debug-helpers.h:
there are examples of their use in monograph, mint and the jit as well.
You basically use a string description of the method, like:

	"System.Object:GetHashCode()"
and create a MonoMethodDesc out of it with:

MonoMethodDesc* mono_method_desc_new (const char *name, gboolean include_namespace);

You can then use:
MonoMethod*     mono_method_desc_search_in_class (MonoMethodDesc *desc, MonoClass *klass);
MonoMethod*     mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image);

to search for the method in a class or in an image.
You would tipically do this just once at the start of the program and
store the result for reuse somewhere.

> - How do we pass C scalars and arrays to and from managed code?

See above for simple scalar values. To pass arrays around, you'll need
to build the proper MonoArray for the type (and copy the data as needed).

MonoArray*
mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n);

Creates a 1-dimensional array with size n for the type eclass.
Common types are available accessing the mono_defaults structure:

MonoArray* byte_array;
guchar *mydata, *array_data;

byte_array = mono_array_new (mono_domain_get (), mono_defaults.byte_class, 32);
mydata = get_from_db ();
array_data = mono_array_addr (byte_array, char, 0);
memcpy (array_data, mydata, mono_array_length (byte_array));

mono_array_length() returns the number of elements in the array.

If copying the data is too expensive (with large objects), you'll need to 
provide a different accessor, maybe a C# type that implements
ICollection/IList and hook that with internalcalls.

Hope this helps.

lupus

-- 
-----------------------------------------------------------------
lupus@debian.org                                     debian/rules
lupus@ximian.com                             Monkeys do it better