RE: [Mono-dev] COM Interop in Mono
Well, no one has responded yet, so here comes the next email ;-) This work is coming along, so I'd like to get it in svn soon. Would this go under the trunk, as in /trunk/cominterop or something like that? If anyone has a better name, please suggest. Also, I think this work will also be similar to work needed for XPCOM. Should both be in the same lib? Or where can I put shared functionality? Ok, more details. All calls to the RCW's are finding their way to the correct methods on the COM objects. Currently, I find the interface that the method belongs to. I then subtract interface->method.start from the method->slot. This gives me the offset of the method in the interface. I then compensate for whether the interface is IUnknown based or IDispatch based (3 or 7 methods at beginning of vtable). I then call that offset on the correct vtable. Now, more about integrating into mono. To correctly support COM interop in mono, the following functionality is needed. I'm trying to begin to define what the API needs to support. 1. Object Creation 2. Method Calls 3. Object Destruction (will all component wrappers need a finalizer?) 4. Casting (more difficult for me, can be supported later as this dynamically adds interfaces to an object) 5. Interface/COM object marshalling 6. BSTR marshalling (I think this should be in this library, so mono has no dependencies on the Sys*String routines for BSTRS) Some humble beginning like: /* creates unmanaged object */ gpointer component_create(MonoObject* this); /* destroys unmanaged object */ void component_destroy(MonoObject * this); /* gets managed->unmanaged wrapper for method calls, called by mono_marshal_get_native_wrapper? */ MonoMethod * component_get_method (MonoMethod *method) Not sure about the marshalling yet... Thanks, Jonathan -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Jonathan S. Chambers Sent: Monday, November 14, 2005 10:06 PM Cc: mono-devel-list@lists.ximian.com Subject: [Mono-dev] COM Interop in Mono Hello all, Here is a brief overview of some work involving COM Interop support in mono. I'm sure I'm wrong on multiple things below, so feel free to suggest/correct. COM Standard Don't feel like saying alot. Lots of docs available. MS COM Interop Again, well documented. Especially via '.NET and COM: The Complete Interoperability Guide' by Adam Nathan. COM interop is twofold. 1. Managed Client, COM Server - This allows for unmanaged com components to be used in the managed runtime. This occurs via runtime callable wrappers (RCW). The RCW is a managed wrapper that manages a single unmanaged com object. The lifetime of the COM object is managed via the RCW; the RCW's lifetime is managed like any other managed object. Also, the interop can occur via early binding (using the Interop assembly and vtables) or late binding via reflection. 2. COM Client, Managed Server - In this case, an managed object is exposed to COM via a COM callable wrapper (CCW). The CCW behaves like a normal COM object to the client. The CCW exposes interfaces corresponding to the managed object's methods/properties, as well as IUnknown, IDispatch, and other interfaces. Another thing to note about COM interop is the runtime support for casting. Normal managed objects fail upon a cast when an interface is not implemented by that object. A RCW will try to cast the normal way, via the metadata provided about the class. If the cast fails, the runtime will then call QueryInterface on the underlying COM object for the interface in question. If the QueryInterface succeeds, then the runtime allows the cast to occur. I'm ignoring other semi-important (depending on your situation) aspects of COM interop such as COM threading, connection points, etc. Old Approach (all in C#, runtime agnostic; i.e. worked on MS. Net and Mono) I'm not going to spend much time on this. This work initially grew out of looking at some code by Peter Bartok in Win32Dnd.cs in MWF. A COM interface (really just a vtable) is essentially a structure of function pointers. Function pointers can be marshalled as delegates (in 2.0) and vice versa. So, for each COM interface a corresponding struct of delegates was defined; except, the all the method signatures were modified to take an IntPtr as the first argument, the 'this; pointer. Once the COM object was created, it was QI'd for that interface. Then, the returned pointer (which points to the vtable) was read via Marshal.ReadIntPtr. This value is then marshalled as the struct previously defined. The delegates can now be invoked. In addition, custom marshallers were written for the marshalling of interfaces and BSTRs. Tricks were played with pinning, GCHandles, etc for lifetime management. Also, to get around the fact that there was no runtime support for 'late' casting, Reflection.Rmit was used to build dynamic wrappers. This method proved useful, but ugly and inefficient to say the least. Current Approach
Re: [Mono-dev] COM Interop in Mono
Hi, You are referencing something that you want to upload to SVN but did not show it yet. What is it exactly? Note that there were discussions about COM interop previously you should look at them as well. Some important things: COM is Windows specific. If you want to use it you can use MS.NET instead of Mono as relaying on COM interop is platform dependent. So there is no use to implement COM interop only for use with Windows. On the other hand COM interop could be implemented as a platform independent object oriented P/Invoke-like layer that could be cool. But the problem is that on Windows COM specifies a standard ABI (Application Binary Interface) for representing COM objects that can be accessed by code compiled using different compilers. On other platforms (Linux for example) there is no standard ABI for objects, only for classic C functions. This makes the things difficult. In addition things like XPCOM assume that you use the same compiler on both sides of interop so has no specific ABI, it depends on the C++ compiler you use. Some people would like to implement COM interop as Bonobo interop in Mono but these two layers are so much different that it cannot be done. Bonobo interop has to be implemented separatedly as it requires different interop attributes for example. Kornél - Original Message - From: "Jonathan S. Chambers" <[EMAIL PROTECTED]> To: "Jonathan S. Chambers" <[EMAIL PROTECTED]> Cc: Sent: Wednesday, November 16, 2005 5:50 PM Subject: RE: [Mono-dev] COM Interop in Mono Well, no one has responded yet, so here comes the next email ;-) This work is coming along, so I'd like to get it in svn soon. Would this go under the trunk, as in /trunk/cominterop or something like that? If anyone has a better name, please suggest. Also, I think this work will also be similar to work needed for XPCOM. Should both be in the same lib? Or where can I put shared functionality? Ok, more details. All calls to the RCW's are finding their way to the correct methods on the COM objects. Currently, I find the interface that the method belongs to. I then subtract interface->method.start from the method->slot. This gives me the offset of the method in the interface. I then compensate for whether the interface is IUnknown based or IDispatch based (3 or 7 methods at beginning of vtable). I then call that offset on the correct vtable. Now, more about integrating into mono. To correctly support COM interop in mono, the following functionality is needed. I'm trying to begin to define what the API needs to support. 1. Object Creation 2. Method Calls 3. Object Destruction (will all component wrappers need a finalizer?) 4. Casting (more difficult for me, can be supported later as this dynamically adds interfaces to an object) 5. Interface/COM object marshalling 6. BSTR marshalling (I think this should be in this library, so mono has no dependencies on the Sys*String routines for BSTRS) Some humble beginning like: /* creates unmanaged object */ gpointer component_create(MonoObject* this); /* destroys unmanaged object */ void component_destroy(MonoObject * this); /* gets managed->unmanaged wrapper for method calls, called by mono_marshal_get_native_wrapper? */ MonoMethod * component_get_method (MonoMethod *method) Not sure about the marshalling yet... Thanks, Jonathan -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Jonathan S. Chambers Sent: Monday, November 14, 2005 10:06 PM Cc: mono-devel-list@lists.ximian.com Subject: [Mono-dev] COM Interop in Mono Hello all, Here is a brief overview of some work involving COM Interop support in mono. I'm sure I'm wrong on multiple things below, so feel free to suggest/correct. COM Standard Don't feel like saying alot. Lots of docs available. MS COM Interop Again, well documented. Especially via '.NET and COM: The Complete Interoperability Guide' by Adam Nathan. COM interop is twofold. 1. Managed Client, COM Server - This allows for unmanaged com components to be used in the managed runtime. This occurs via runtime callable wrappers (RCW). The RCW is a managed wrapper that manages a single unmanaged com object. The lifetime of the COM object is managed via the RCW; the RCW's lifetime is managed like any other managed object. Also, the interop can occur via early binding (using the Interop assembly and vtables) or late binding via reflection. 2. COM Client, Managed Server - In this case, an managed object is exposed to COM via a COM callable wrapper (CCW). The CCW behaves like a normal COM object to the client. The CCW exposes interfaces corresponding to the managed object's methods/properties, as well as IUnknown, IDispatch, and other interfaces. Another thing to note about COM interop is the runtime support for casting. Normal managed objects fail upon a cast when an interface is not implemented by that objec
RE: [Mono-dev] COM Interop in Mono
Attached is a diff of some current progress. These changes are all in place right now, they would of course need moved to an external library. Kornel, to answer your questions: This is intended to be the beginning of a framework to leverage multiple component technologies. COM Interop is well defined so I'm starting there. COM is not necessarily Windows specific. It can be ported via tools (such as those provided by Mainsoft) or on one's own if you follow the COM ABI standard. As for XPCOM, I know little about it. I've looked into it a little, and while it may not have as well defined an ABI, there may still be hope for it. - Jonathan -Original Message- From: Kornél Pál [mailto:[EMAIL PROTECTED] Sent: Wednesday, November 16, 2005 1:07 PM To: Jonathan S. Chambers Cc: mono-devel-list@lists.ximian.com Subject: Re: [Mono-dev] COM Interop in Mono Hi, You are referencing something that you want to upload to SVN but did not show it yet. What is it exactly? Note that there were discussions about COM interop previously you should look at them as well. Some important things: COM is Windows specific. If you want to use it you can use MS.NET instead of Mono as relaying on COM interop is platform dependent. So there is no use to implement COM interop only for use with Windows. On the other hand COM interop could be implemented as a platform independent object oriented P/Invoke-like layer that could be cool. But the problem is that on Windows COM specifies a standard ABI (Application Binary Interface) for representing COM objects that can be accessed by code compiled using different compilers. On other platforms (Linux for example) there is no standard ABI for objects, only for classic C functions. This makes the things difficult. In addition things like XPCOM assume that you use the same compiler on both sides of interop so has no specific ABI, it depends on the C++ compiler you use. Some people would like to implement COM interop as Bonobo interop in Mono but these two layers are so much different that it cannot be done. Bonobo interop has to be implemented separatedly as it requires different interop attributes for example. Kornél - Original Message - From: "Jonathan S. Chambers" <[EMAIL PROTECTED]> To: "Jonathan S. Chambers" <[EMAIL PROTECTED]> Cc: Sent: Wednesday, November 16, 2005 5:50 PM Subject: RE: [Mono-dev] COM Interop in Mono Well, no one has responded yet, so here comes the next email ;-) This work is coming along, so I'd like to get it in svn soon. Would this go under the trunk, as in /trunk/cominterop or something like that? If anyone has a better name, please suggest. Also, I think this work will also be similar to work needed for XPCOM. Should both be in the same lib? Or where can I put shared functionality? Ok, more details. All calls to the RCW's are finding their way to the correct methods on the COM objects. Currently, I find the interface that the method belongs to. I then subtract interface->method.start from the method->slot. This gives me the offset of the method in the interface. I then compensate for whether the interface is IUnknown based or IDispatch based (3 or 7 methods at beginning of vtable). I then call that offset on the correct vtable. Now, more about integrating into mono. To correctly support COM interop in mono, the following functionality is needed. I'm trying to begin to define what the API needs to support. 1. Object Creation 2. Method Calls 3. Object Destruction (will all component wrappers need a finalizer?) 4. Casting (more difficult for me, can be supported later as this dynamically adds interfaces to an object) 5. Interface/COM object marshalling 6. BSTR marshalling (I think this should be in this library, so mono has no dependencies on the Sys*String routines for BSTRS) Some humble beginning like: /* creates unmanaged object */ gpointer component_create(MonoObject* this); /* destroys unmanaged object */ void component_destroy(MonoObject * this); /* gets managed->unmanaged wrapper for method calls, called by mono_marshal_get_native_wrapper? */ MonoMethod * component_get_method (MonoMethod *method) Not sure about the marshalling yet... Thanks, Jonathan -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Jonathan S. Chambers Sent: Monday, November 14, 2005 10:06 PM Cc: mono-devel-list@lists.ximian.com Subject: [Mono-dev] COM Interop in Mono Hello all, Here is a brief overview of some work involving COM Interop support in mono. I'm sure I'm wrong on multiple things below, so feel free to suggest/correct. COM Standard Don't feel like saying alot. Lots of docs available. MS COM Interop Again, well documented. Especially via '.NET and COM: The Complete Interoperability Guide' by Adam Nathan. COM interop is twofold. 1. Managed Client, COM Server - This allows
Re: [Mono-dev] COM Interop in Mono
Hi, The attached code looks promising. I absolutely agree with you that any kind of ABI (including COM ABI) can be implemented. The problem that I tried to point out is however that implementing COM interop in Mono using an ABI that cannot be accessed by compilers is useless. On Windows you can simply use COM ABI as a C++ object because the compiler has support for that ABI. If you use the same ABI on Linux for example without having a C++ compiler that supports the same ABI you will not be able to use COM interop on that platform (unless you use assembly code for example to produce the same calls). So it's OK to implement COM ABI in Mono but do you have a compiler on the other side of interop with support for the same ABI? If you want to undersand MS.NET COM interop correctly you should look at Mashal class. Methods and documentations as well. As I see all the functionality suported by COM interop layer is available through Marshal class as well that helps to understand it's infrastructure. You mentioned in one of your previous messages that COM methods have HRESULT return value. This is only optional. They can have any return type. When using PreserveSigAttribute the original signature is used instead of using HRESULT as return value and transofrming return value to parameter. This means that there is no HRESULT <-> exception mapping done by the runtime. You should have a look at mcs/class/System.Drawing/System.Drawing/ComIStreamMarshaler.cs as well. This is implemented in pure C# so Peter's work is somehow nearer to runtime level but my work is more similar to MS.NET COM interop in it's behavior. There are some differences like MS.NET uses the same QueryInterface, AddRef and Release implementations and don't have to set out parameter when error is returned in HRESULT but is very similar. Also note that MS.NET COM interop has cross-AppDomain marshaling support unlike delegate marshaling. If you need help in undersanding COM interop infrastrucutre or a specific functionality feel free to ask me. Kornél - Original Message - From: "Jonathan S. Chambers" <[EMAIL PROTECTED]> To: "Kornél Pál" <[EMAIL PROTECTED]> Cc: Sent: Wednesday, November 16, 2005 7:49 PM Subject: RE: [Mono-dev] COM Interop in Mono Attached is a diff of some current progress. These changes are all in place right now, they would of course need moved to an external library. Kornel, to answer your questions: This is intended to be the beginning of a framework to leverage multiple component technologies. COM Interop is well defined so I'm starting there. COM is not necessarily Windows specific. It can be ported via tools (such as those provided by Mainsoft) or on one's own if you follow the COM ABI standard. As for XPCOM, I know little about it. I've looked into it a little, and while it may not have as well defined an ABI, there may still be hope for it. - Jonathan -Original Message- From: Kornél Pál [mailto:[EMAIL PROTECTED] Sent: Wednesday, November 16, 2005 1:07 PM To: Jonathan S. Chambers Cc: mono-devel-list@lists.ximian.com Subject: Re: [Mono-dev] COM Interop in Mono Hi, You are referencing something that you want to upload to SVN but did not show it yet. What is it exactly? Note that there were discussions about COM interop previously you should look at them as well. Some important things: COM is Windows specific. If you want to use it you can use MS.NET instead of Mono as relaying on COM interop is platform dependent. So there is no use to implement COM interop only for use with Windows. On the other hand COM interop could be implemented as a platform independent object oriented P/Invoke-like layer that could be cool. But the problem is that on Windows COM specifies a standard ABI (Application Binary Interface) for representing COM objects that can be accessed by code compiled using different compilers. On other platforms (Linux for example) there is no standard ABI for objects, only for classic C functions. This makes the things difficult. In addition things like XPCOM assume that you use the same compiler on both sides of interop so has no specific ABI, it depends on the C++ compiler you use. Some people would like to implement COM interop as Bonobo interop in Mono but these two layers are so much different that it cannot be done. Bonobo interop has to be implemented separatedly as it requires different interop attributes for example. Kornél - Original Message - From: "Jonathan S. Chambers" <[EMAIL PROTECTED]> To: "Jonathan S. Chambers" <[EMAIL PROTECTED]> Cc: Sent: Wednesday, November 16, 2005 5:50 PM Subject: RE: [Mono-dev] COM Interop in Mono Well, no one has responded yet, so here comes the next email ;-) This work is coming along, so I'd like to get it in svn soon. Would this go under the trunk, as in /trunk/cominterop or something like that? If anyone has a
RE: [Mono-dev] COM Interop in Mono
Well, I am by no means an expert on ABIs of different compilers. But, I have built a small COM style object on linux using gcc, and have been able to use it from managed code with my own flavor of COM interop. Is that pure luck, I don't know? ;-) I understand that much of the infrastructure of COM interop is exposed via the Marshal class. However, none of that functionality is currently implemented in mono. That is what I am trying to do. COM methods don't have to return HRESULTS, but all that I am currently testing with does. I'll fix that assumption later. As for the cross app domain marshalling and whatever wonderful features exist, I am not worried about that right now. If I can use a COM object in C# within a single threaded/app domain environment, I will be happy. I have looked at your code in ComIStreamMarshaler (and Peter's in Win32Dnd). That was the source for what I did in previous attempts at COM Interop (see original email). The code is ugly right now, but I would appreciate any help/advice as it moves forward. Thanks, Jonathan -Original Message- From: Kornél Pál [mailto:[EMAIL PROTECTED] Sent: Wednesday, November 16, 2005 2:31 PM To: Jonathan S. Chambers Cc: mono-devel-list@lists.ximian.com Subject: Re: [Mono-dev] COM Interop in Mono Hi, The attached code looks promising. I absolutely agree with you that any kind of ABI (including COM ABI) can be implemented. The problem that I tried to point out is however that implementing COM interop in Mono using an ABI that cannot be accessed by compilers is useless. On Windows you can simply use COM ABI as a C++ object because the compiler has support for that ABI. If you use the same ABI on Linux for example without having a C++ compiler that supports the same ABI you will not be able to use COM interop on that platform (unless you use assembly code for example to produce the same calls). So it's OK to implement COM ABI in Mono but do you have a compiler on the other side of interop with support for the same ABI? If you want to undersand MS.NET COM interop correctly you should look at Mashal class. Methods and documentations as well. As I see all the functionality suported by COM interop layer is available through Marshal class as well that helps to understand it's infrastructure. You mentioned in one of your previous messages that COM methods have HRESULT return value. This is only optional. They can have any return type. When using PreserveSigAttribute the original signature is used instead of using HRESULT as return value and transofrming return value to parameter. This means that there is no HRESULT <-> exception mapping done by the runtime. You should have a look at mcs/class/System.Drawing/System.Drawing/ComIStreamMarshaler.cs as well. This is implemented in pure C# so Peter's work is somehow nearer to runtime level but my work is more similar to MS.NET COM interop in it's behavior. There are some differences like MS.NET uses the same QueryInterface, AddRef and Release implementations and don't have to set out parameter when error is returned in HRESULT but is very similar. Also note that MS.NET COM interop has cross-AppDomain marshaling support unlike delegate marshaling. If you need help in undersanding COM interop infrastrucutre or a specific functionality feel free to ask me. Kornél - Original Message - From: "Jonathan S. Chambers" <[EMAIL PROTECTED]> To: "Kornél Pál" <[EMAIL PROTECTED]> Cc: Sent: Wednesday, November 16, 2005 7:49 PM Subject: RE: [Mono-dev] COM Interop in Mono Attached is a diff of some current progress. These changes are all in place right now, they would of course need moved to an external library. Kornel, to answer your questions: This is intended to be the beginning of a framework to leverage multiple component technologies. COM Interop is well defined so I'm starting there. COM is not necessarily Windows specific. It can be ported via tools (such as those provided by Mainsoft) or on one's own if you follow the COM ABI standard. As for XPCOM, I know little about it. I've looked into it a little, and while it may not have as well defined an ABI, there may still be hope for it. - Jonathan -Original Message- From: Kornél Pál [mailto:[EMAIL PROTECTED] Sent: Wednesday, November 16, 2005 1:07 PM To: Jonathan S. Chambers Cc: mono-devel-list@lists.ximian.com Subject: Re: [Mono-dev] COM Interop in Mono Hi, You are referencing something that you want to upload to SVN but did not show it yet. What is it exactly? Note that there were discussions about COM interop previously you should look at them as well. Some important things: COM is Windows specific. If you want to use it you can use MS.NET instead of Mono as relaying on COM interop is platform dependent. So there is no use to implement COM interop only for use with Windows. On the other hand COM interop could be imp
RE: [Mono-dev] COM Interop in Mono
Anyone have any advice about beginning to make this all an external library accessible to mono? Where does it go? How is mono aware of it/find it? How does mono load it/call methods, etc. Thanks, Jonathan -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Jonathan S. Chambers Sent: Wednesday, November 16, 2005 3:08 PM To: Kornél Pál Cc: mono-devel-list@lists.ximian.com Subject: RE: [Mono-dev] COM Interop in Mono Well, I am by no means an expert on ABIs of different compilers. But, I have built a small COM style object on linux using gcc, and have been able to use it from managed code with my own flavor of COM interop. Is that pure luck, I don't know? ;-) I understand that much of the infrastructure of COM interop is exposed via the Marshal class. However, none of that functionality is currently implemented in mono. That is what I am trying to do. COM methods don't have to return HRESULTS, but all that I am currently testing with does. I'll fix that assumption later. As for the cross app domain marshalling and whatever wonderful features exist, I am not worried about that right now. If I can use a COM object in C# within a single threaded/app domain environment, I will be happy. I have looked at your code in ComIStreamMarshaler (and Peter's in Win32Dnd). That was the source for what I did in previous attempts at COM Interop (see original email). The code is ugly right now, but I would appreciate any help/advice as it moves forward. Thanks, Jonathan -Original Message- From: Kornél Pál [mailto:[EMAIL PROTECTED] Sent: Wednesday, November 16, 2005 2:31 PM To: Jonathan S. Chambers Cc: mono-devel-list@lists.ximian.com Subject: Re: [Mono-dev] COM Interop in Mono Hi, The attached code looks promising. I absolutely agree with you that any kind of ABI (including COM ABI) can be implemented. The problem that I tried to point out is however that implementing COM interop in Mono using an ABI that cannot be accessed by compilers is useless. On Windows you can simply use COM ABI as a C++ object because the compiler has support for that ABI. If you use the same ABI on Linux for example without having a C++ compiler that supports the same ABI you will not be able to use COM interop on that platform (unless you use assembly code for example to produce the same calls). So it's OK to implement COM ABI in Mono but do you have a compiler on the other side of interop with support for the same ABI? If you want to undersand MS.NET COM interop correctly you should look at Mashal class. Methods and documentations as well. As I see all the functionality suported by COM interop layer is available through Marshal class as well that helps to understand it's infrastructure. You mentioned in one of your previous messages that COM methods have HRESULT return value. This is only optional. They can have any return type. When using PreserveSigAttribute the original signature is used instead of using HRESULT as return value and transofrming return value to parameter. This means that there is no HRESULT <-> exception mapping done by the runtime. You should have a look at mcs/class/System.Drawing/System.Drawing/ComIStreamMarshaler.cs as well. This is implemented in pure C# so Peter's work is somehow nearer to runtime level but my work is more similar to MS.NET COM interop in it's behavior. There are some differences like MS.NET uses the same QueryInterface, AddRef and Release implementations and don't have to set out parameter when error is returned in HRESULT but is very similar. Also note that MS.NET COM interop has cross-AppDomain marshaling support unlike delegate marshaling. If you need help in undersanding COM interop infrastrucutre or a specific functionality feel free to ask me. Kornél - Original Message - From: "Jonathan S. Chambers" <[EMAIL PROTECTED]> To: "Kornél Pál" <[EMAIL PROTECTED]> Cc: Sent: Wednesday, November 16, 2005 7:49 PM Subject: RE: [Mono-dev] COM Interop in Mono Attached is a diff of some current progress. These changes are all in place right now, they would of course need moved to an external library. Kornel, to answer your questions: This is intended to be the beginning of a framework to leverage multiple component technologies. COM Interop is well defined so I'm starting there. COM is not necessarily Windows specific. It can be ported via tools (such as those provided by Mainsoft) or on one's own if you follow the COM ABI standard. As for XPCOM, I know little about it. I've looked into it a little, and while it may not have as well defined an ABI, there may still be hope for it. - Jonathan -Original Message- From: Kornél Pál [mailto:[EMAIL PROTECTED] Sent: Wednesday, November 16, 2005 1:07 PM To: Jonathan S. Chambers Cc: mono-devel-list@lists.ximian.com Subject: Re: [Mono-dev] COM Interop in Mono Hi, You ar
Re: [Mono-dev] COM Interop in Mono
On 11/16/05 Jonathan S. Chambers wrote: > Attached is a diff of some current progress. These changes are all in > place right now, they would of course need moved to an external library. Thanks for the patch. I don't think this stuff should be moved to a library, at least not until it's windows-only. Moving to a module may be needed later if we support other COM-like systems using the same interface, but that is likely way off. > Index: metadata/class.c > === > --- metadata/class.c (revision 52794) > +++ metadata/class.c (working copy) > @@ -2682,6 +2682,12 @@ > g_assert (class->field.count == 0); > } > > + /* reserve space to store COM object pointer in RCW */ > + if (class->flags & TYPE_ATTRIBUTE_IMPORT && > !MONO_CLASS_IS_INTERFACE(class)) { > + class->instance_size += 2 * sizeof (gpointer); Reserve room just for one pointer. > Index: metadata/object-internals.h > === > --- metadata/object-internals.h (revision 52794) > +++ metadata/object-internals.h (working copy) > @@ -993,6 +993,17 @@ > guint32 location; > } MonoManifestResourceInfo; > > + > +typedef struct { > + MonoObject object; > + MonoString *guid; > +} MonoReflectionGuidAttribute; > + > +typedef struct { > + MonoObject object; > + guint16 intType; > +} MonoInterfaceTypeAttribute; Add also a: typedef struct { MonoObject object; gpointer comptr; } MonoCOMWrapper; and always use it instead of doing pointer arithmetric etc. > Index: metadata/marshal.c > === > --- metadata/marshal.c(revision 52794) > +++ metadata/marshal.c(working copy) > @@ -6309,6 +6309,279 @@ > mono_mb_emit_byte (mb, CEE_RET); > } > > +void > +component_get_object_and_fnc_ptr(MonoObject *this, MonoMethod* method, > gpointer* pObj, gpointer* pFunc) Most of these functions should be static. If they need to be exported, they should be in an header file and have the usual mono_ prefix. > +{ > + IUnknown * pUnk = NULL; > + int ** vtable; > + int i = 0; > + int offset = 0; > + GUID clsid; > + > + for (i = 0; i < method->klass->interface_count; i++) > + { The brace needs to go in the previous line, several of these in the patch. > + int first; > + MonoClass* itf = *(method->klass->interfaces+i); Change to method->klass->interfaces [i]; > + > + first = itf->method.first; > + if (first <= method->slot && first+itf->method.count > > method->slot) Needs spaces around operators like +. > + { > + static MonoClass *GuidAttribute; > + static MonoClass *InterfaceTypeAttribute; > + MonoCustomAttrInfo *cinfo; > + MonoReflectionGuidAttribute *attr; > + MonoInterfaceTypeAttribute* itf_attr; > + > + offset = method->slot - first; > + > + if (!GuidAttribute) > + GuidAttribute = mono_class_from_name > (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute"); You need GuidAttribute already in two places: please add it to the mono_defaults struct. Aso, please use lower case variable names. > + if (!InterfaceTypeAttribute) > + InterfaceTypeAttribute = mono_class_from_name > (mono_defaults.corlib, "System.Runtime.InteropServices", > "InterfaceTypeAttribute"); > + > + if (GuidAttribute) { No need for this check here: if the attribute is not in corlib there are bigger issues and we'd have the proper code to check it somewhere _once_ instead of at each loop iteration. > + cinfo = mono_custom_attrs_from_class (itf); > + if (cinfo) { > + attr = > (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr (cinfo, > GuidAttribute); > + itf_attr = > (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr (cinfo, > InterfaceTypeAttribute); > + if (attr) { > + LPOLESTR temp; > + wchar_t buf[50]; > + > wsprintf(buf,L"{%s}",attr->guid->chars); You're not allowed to access MonoString->chars directly. Use mono_string_chars(). This code though, should avoid creating the object and just access the guid data inside the proper cinfo->data. Of course this code is invariant in the loop, so it should be moved out of it. > + CLSIDFromString(buf, &clsid); > + > ((IUnknown*)*((
RE: [Mono-dev] COM Interop in Mono
Well, Some things are windows only (BSTR marshalling comes to mind), at least for now. Should that not be included at this point, or should it be put inside of an #ifdef? On #mono there was some concern about different levels of support across platforms. Also, if I leave this inside of mono for now, any advice on that? Should I stick all my routines at the bottom of the file for example, or tag them all with a comment, etc.? Thanks, Jonathan -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Paolo Molaro Sent: Thursday, November 17, 2005 11:49 AM To: mono-devel-list@lists.ximian.com Subject: Re: [Mono-dev] COM Interop in Mono On 11/16/05 Jonathan S. Chambers wrote: > Attached is a diff of some current progress. These changes are all in > place right now, they would of course need moved to an external library. Thanks for the patch. I don't think this stuff should be moved to a library, at least not until it's windows-only. Moving to a module may be needed later if we support other COM-like systems using the same interface, but that is likely way off. > Index: metadata/class.c > === > --- metadata/class.c (revision 52794) > +++ metadata/class.c (working copy) > @@ -2682,6 +2682,12 @@ > g_assert (class->field.count == 0); > } > > + /* reserve space to store COM object pointer in RCW */ > + if (class->flags & TYPE_ATTRIBUTE_IMPORT && !MONO_CLASS_IS_INTERFACE(class)) { > + class->instance_size += 2 * sizeof (gpointer); Reserve room just for one pointer. > Index: metadata/object-internals.h > === > --- metadata/object-internals.h (revision 52794) > +++ metadata/object-internals.h (working copy) > @@ -993,6 +993,17 @@ > guint32 location; > } MonoManifestResourceInfo; > > + > +typedef struct { > + MonoObject object; > + MonoString *guid; > +} MonoReflectionGuidAttribute; > + > +typedef struct { > + MonoObject object; > + guint16 intType; > +} MonoInterfaceTypeAttribute; Add also a: typedef struct { MonoObject object; gpointer comptr; } MonoCOMWrapper; and always use it instead of doing pointer arithmetric etc. > Index: metadata/marshal.c > === > --- metadata/marshal.c(revision 52794) > +++ metadata/marshal.c(working copy) > @@ -6309,6 +6309,279 @@ > mono_mb_emit_byte (mb, CEE_RET); > } > > +void > +component_get_object_and_fnc_ptr(MonoObject *this, MonoMethod* method, gpointer* pObj, gpointer* pFunc) Most of these functions should be static. If they need to be exported, they should be in an header file and have the usual mono_ prefix. > +{ > + IUnknown * pUnk = NULL; > + int ** vtable; > + int i = 0; > + int offset = 0; > + GUID clsid; > + > + for (i = 0; i < method->klass->interface_count; i++) > + { The brace needs to go in the previous line, several of these in the patch. > + int first; > + MonoClass* itf = *(method->klass->interfaces+i); Change to method->klass->interfaces [i]; > + > + first = itf->method.first; > + if (first <= method->slot && first+itf->method.count > method->slot) Needs spaces around operators like +. > + { > + static MonoClass *GuidAttribute; > + static MonoClass *InterfaceTypeAttribute; > + MonoCustomAttrInfo *cinfo; > + MonoReflectionGuidAttribute *attr; > + MonoInterfaceTypeAttribute* itf_attr; > + > + offset = method->slot - first; > + > + if (!GuidAttribute) > + GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute"); You need GuidAttribute already in two places: please add it to the mono_defaults struct. Aso, please use lower case variable names. > + if (!InterfaceTypeAttribute) > + InterfaceTypeAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute"); > + > + if (GuidAttribute) { No need for this check here: if the attribute is not in corlib there are bigger issues and we'd have the proper code to check it somewhere _once_ instead of at each loop iteration. > + cinfo = mono_cu
Re: [Mono-dev] COM Interop in Mono
Hi, Unless you want to use it on Linux immediately (and of course if it can be used on Linux), this should be Windows only currently. As such it can be simply #ifdef'd as windows-only. Porting COM interop to Linux will need some support functions exported by Mono to support everiyhing (not all of the listed functions are necessary): http://msdn.microsoft.com/library/en-us/com/html/36563ef5-1523-4b77-bca9-472c39e04785.asp http://msdn.microsoft.com/library/en-us/automat/html/4ecb0c1f-4e4d-4e8b-bd55-9ac6568d027b.asp Kornél - Original Message - From: "Jonathan S. Chambers" <[EMAIL PROTECTED]> To: "Paolo Molaro" <[EMAIL PROTECTED]>; Sent: Thursday, November 17, 2005 5:52 PM Subject: RE: [Mono-dev] COM Interop in Mono Well, Some things are windows only (BSTR marshalling comes to mind), at least for now. Should that not be included at this point, or should it be put inside of an #ifdef? On #mono there was some concern about different levels of support across platforms. Also, if I leave this inside of mono for now, any advice on that? Should I stick all my routines at the bottom of the file for example, or tag them all with a comment, etc.? Thanks, Jonathan -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Paolo Molaro Sent: Thursday, November 17, 2005 11:49 AM To: mono-devel-list@lists.ximian.com Subject: Re: [Mono-dev] COM Interop in Mono On 11/16/05 Jonathan S. Chambers wrote: Attached is a diff of some current progress. These changes are all in place right now, they would of course need moved to an external library. Thanks for the patch. I don't think this stuff should be moved to a library, at least not until it's windows-only. Moving to a module may be needed later if we support other COM-like systems using the same interface, but that is likely way off. Index: metadata/class.c === --- metadata/class.c (revision 52794) +++ metadata/class.c (working copy) @@ -2682,6 +2682,12 @@ g_assert (class->field.count == 0); } + /* reserve space to store COM object pointer in RCW */ + if (class->flags & TYPE_ATTRIBUTE_IMPORT && !MONO_CLASS_IS_INTERFACE(class)) { + class->instance_size += 2 * sizeof (gpointer); Reserve room just for one pointer. Index: metadata/object-internals.h === --- metadata/object-internals.h (revision 52794) +++ metadata/object-internals.h (working copy) @@ -993,6 +993,17 @@ guint32 location; } MonoManifestResourceInfo; + +typedef struct { + MonoObject object; + MonoString *guid; +} MonoReflectionGuidAttribute; + +typedef struct { + MonoObject object; + guint16 intType; +} MonoInterfaceTypeAttribute; Add also a: typedef struct { MonoObject object; gpointer comptr; } MonoCOMWrapper; and always use it instead of doing pointer arithmetric etc. Index: metadata/marshal.c === --- metadata/marshal.c (revision 52794) +++ metadata/marshal.c (working copy) @@ -6309,6 +6309,279 @@ mono_mb_emit_byte (mb, CEE_RET); } +void +component_get_object_and_fnc_ptr(MonoObject *this, MonoMethod* method, gpointer* pObj, gpointer* pFunc) Most of these functions should be static. If they need to be exported, they should be in an header file and have the usual mono_ prefix. +{ + IUnknown * pUnk = NULL; + int ** vtable; + int i = 0; + int offset = 0; + GUID clsid; + + for (i = 0; i < method->klass->interface_count; i++) + { The brace needs to go in the previous line, several of these in the patch. + int first; + MonoClass* itf = *(method->klass->interfaces+i); Change to method->klass->interfaces [i]; + + first = itf->method.first; + if (first <= method->slot && first+itf->method.count > method->slot) Needs spaces around operators like +. + { + static MonoClass *GuidAttribute; + static MonoClass *InterfaceTypeAttribute; + MonoCustomAttrInfo *cinfo; + MonoReflectionGuidAttribute *attr; + MonoInterfaceTypeAttribute* itf_attr; + + offset = method->slot - first; + + if (!GuidAttribute) + GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute"); You need GuidAttribute already in two places: please add it to the mono_defaults struct. Aso, please use lower case variable names. + if (!InterfaceTypeAttribute) + InterfaceTypeAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute"); + + if (GuidAttribute) { No need for this check here: if the attribute is not in corlib there are bigger issues and we'd have the proper code to check it somewhere _once_ instead of at each loop iteration. + cinfo = mono_custom_attrs_from_class (itf); + if (cinfo) { + att
RE: [Mono-dev] COM Interop in Mono
First, thanks a ton to Jonathan Pryor, Paolo Molaro, and Lluis Sanchez (and any others) for their help. So, previously I was able to create a class from an interop assembly and use that class in managed (casting, calling methods, etc. successfully interacting with the underlying COM object). That was only for COM objects whose coclass metadata was defined in the interop assembly. Now, arbitrary COM interfaces can be handled, even if the object is not a coclass or if the coclass is not defined in the interop assembly. In other words, a COM interface can be marshaled back to managed as long as that interface is defined in an interop assembly. I'll described the process (I'll post code later, it's too ugly right now as I just got it working). It begins with a method/property returning a parameter/value that is marked to be marshalled as an interface (meaning COM interface). This will invoke the marshaller. At this point, all that is assumed is that the pointer is a COM interface. The managed method has a target interface for the pointer. This target interface is queried for a GuidAttribute. The guid is then used to call QueryInterface on the underlying COM object to verify that the object does indeed support that interface. I created new class, ComProxy, that derives from RealProxy. An instance of ComProxy is created for type System.__ComObject, and the COM interface pointer is stored in the ComProxy object in an IntPtr field. Next, GetTransparentProxy is called on the ComProxy object. This transparent proxy is then cast to the target interface. ComProxy also implements System.Runtime.Remoting.IRemotingTypeInfo, which has a method CanCastTo. This method is called the first time the transparent proxy is cast to a new type. In this method, it is verified that the underlying COM object supports an interface via the method mentioned previously (calling QI with the interface GUID). If a cast can proceed, then special logic occurs because the object is a transparent proxy. The interface is added to the interface table, and the additional methods are added to the vtable. Normally, these vtable slots are filled with trampolines for remoting calls. However, in the COM case I emit trampolines that call the underlying COM object. So, much is done yet much remains ;-). If anyone has any questions please ask. TODO: 1. A lot of marshalling code. Currently, the System.Object type is not marshalled at all. This needs implemented for VARIANT, IUnknown, and IDispatch types. 2. Currently I'm not even going through the default marshalling code. I need to use this and adjust it for COM rules rather than pinvoke rules when using COM Interop. 3. Add finalizer logic so that COM objects will be released during finalization. Need to look into the thread issues with this, as finalization may not occur on the thread that the COM object was created on. 4. Right now, I store the IUnknown pointer. I really need an array/list of pointers that are indexed by interface. Thus, I only need to QueryInterface for each interface once. I do it on every method call currently. 5. Try this with XPCOM, or a cross platform COM solution. 6. Connection points/events. 7. COM Callable Wrappers - exposing managed objects to COM - Jonathan -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Jonathan S. Chambers Sent: Thursday, November 17, 2005 11:52 AM To: Paolo Molaro; mono-devel-list@lists.ximian.com Subject: RE: [Mono-dev] COM Interop in Mono Well, Some things are windows only (BSTR marshalling comes to mind), at least for now. Should that not be included at this point, or should it be put inside of an #ifdef? On #mono there was some concern about different levels of support across platforms. Also, if I leave this inside of mono for now, any advice on that? Should I stick all my routines at the bottom of the file for example, or tag them all with a comment, etc.? Thanks, Jonathan -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Paolo Molaro Sent: Thursday, November 17, 2005 11:49 AM To: mono-devel-list@lists.ximian.com Subject: Re: [Mono-dev] COM Interop in Mono On 11/16/05 Jonathan S. Chambers wrote: > Attached is a diff of some current progress. These changes are all in > place right now, they would of course need moved to an external library. Thanks for the patch. I don't think this stuff should be moved to a library, at least not until it's windows-only. Moving to a module may be needed later if we support other COM-like systems using the same interface, but that is likely way off. > Index: metadata/class.c > === > --- metadata/class.c (revision 52794) > +++ metadata/class.c (working copy) > @@ -2682,6 +2682,12 @@ > g_assert (class->field.count == 0); > } > > + /* res