[Mono-dev] Unmanaged Component Interop in Mono

Jonathan S. Chambers Jonathan.Chambers at ansys.com
Thu Mar 23 13:32:53 EST 2006


It's been a while since there was an update on COM Interop in mono, mainly due to my schedule. But, my schedule is going to free up after next week. I hope to get some COM stuff done among other things.

So, previous posts/patches have already been sent to this list. I can continue to work on them as they are, but I wanted to put out an idea for a general unmanaged component interop mechanism. I've thought about this in the context of COM, XPCOM, and Open Office's UNO, although I'm hoping it will work for any system. So, here goes:

This system is a blend of MS Com Interop, and the various mechanisms others have used to get components into mono (see shaver/zbowling with XPCOM, or Open Office work). Hopefully, MS Com interop will work out of the box on mono as it does on .Net. Extensions will allow the other component systems to work.

I'll describe an interface based approach (this covers COM, XPCOM, and UNO I believe among others).

Let's start with an unmanaged component called CFastMath. This component implements IAdd and ISubtract. Something like:

class CFastMath : public IAdd, public ISubtract
{
	...
	// IAdd methods
	// ISubstract methods
}


For COM Interop the managed definition looks something like:

[Guid("...")]
[ComImport()]
interface IAdd
{
}

[Guid("...")]
[ComImport()]
inteface ISubtract
{
}


[Guid("...")]
[ComImport()]
class FastMath : IAdd, ISubtract
{
	// IAdd methods
	// ISubtract methods

	// methods have runtime managed and internalcall attributes
}

So, when the class is created, the runtime knows this wraps a COM object. It creates the underlying unmanaged object and forwards calls to that object.

So, in order to handle other component systems like XPCOM for example, the setup is exactly the same, except we add another attribute.

[Guid("...")]
[ComImport()]
[Mono.Components.ComponentManager(typeof(XPCOMManager))]
class FastMath : IAdd, ISubtract
{
	// IAdd methods
	// ISubtract methods

	// methods have runtime managed and internalcall attributes
}

So, this additional attribute takes a type that specifies the manager for this type of component. If we don't find this attribute we assume normal COM Interop, else we use this manager. At this point, the manager has a very simple role. It has to implement the methods on the class (it would probably also store a lot of utility methods). Right now in the runtime, I handle ComImport objects specially. When a method needs implemented, I emit the wrapper code needed to call the unmanaged object. My proposal is to move this to managed, and allow the various component managers to emit this code.

If I look at my changes to the runtime, I only really need 2/3 hooks in there; the rest of the code could be managed. The UNO work uses objects derived from MarshalByRef object and works via a proxy; they handle the method calls in the Invoke method via messages. This is very close to what I'm proposing except remove the Message layer for performance reasons. Give people a hook to directly emit code for the methods, rather than having to handle a message.

So, the manager object has a method that takes a method info and returns the emitted method. The is pretty much possible right now using the DynamicMethod class (or we could create a very simlar class in the component namespace). So, when the FastMethod class is created, the .ctor code is emitted by the manager. The manager emits code for the constructor to create the unmanaged object and store it. Subsequent method calls are similarly resolved by the manager emitting code to invoke the methods on the underlying unmanaged objects. Deriving from MarshalByRef object and using a proxy object is what allows for 'late' casting (allow casting to succeed depending on a QueryInterface call). We could continue to use this method, or provide another hook for casting calls. If they succeed the methods would again be dynamically emitted by the manager.

The nice thing is that the pinvoke/marshalling layer would still work. The user only has to marshal special types (interfaces, strings, etc).  The types that the marshalling layer already handles would still work.

In short, this gets a lot of component interop code out of the runtime. It also opens up a way for mono to support a variety of component systems without people having to modify the runtime.

Thoughts?


Jonathan S. Chambers
Software Development Engineer
ANSYS, Inc.
Phone: 724.514.3682
Fax: 724.514.3114
E-mail: jonathan.chambers at ansys.com
 
___________________________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer.





More information about the Mono-devel-list mailing list