Our porting work depends on having a link from C# to C++ using COM. This is a fundamental requirement, and without it we cannot proceed. Although we’ve had this working in small test programs for a long time, it would crash badly when we tried it with our application (WorldPad, part of FieldWorks). We were fairly sure it was something we were doing wrong, but could never pin it down. Well, now Tom and Brent have found the solution!
The .Net specification provides a way for managed code (eg C#) to instantiate COM objects (eg C++) and call methods on them. This is very important in FieldWorks because the majority of the application code is C#, but makes use of some very powerful infrastructure code written in C++. The seamless joining of C# and C++ via COM in .Net is a huge advantage.
The Mono developers have thoughtfully provided the same capabilities in the Mono runtime as are available in .Net. This means that, on Windows, Mono works exactly as expected with Microsoft’s COM implementation. Surprisingly, the same capability also exists in the Linux version of Mono, except that there’s no COM implementation there. However, they have arranged things such that if a library exists with the right name, and provides exactly the right functions, then Mono will use that library to do COM on Linux.
This has been used by others with a commercial Windows- to- Unix porting library, but never with an open-source library. We developed libcom to be just such a library, designed to be lightweight, with very few dependencies, and doing just one thing well. Because libcom implements the COM APIs exactly according to spec, and Mono uses them exactly according to the same spec, it turns out that Mono works perfectly with libcom. We are able to create and use COM objects implemented in C++ from C#, and vice versa. But only in small test programs. Until now.
In order for the managed runtime to know what interfaces and methods a given COM object supports, there needs to be a special .Net assembly, called an interop, that defines .Net classes with special attributes that mark them as “stand-ins” for their COM counterparts. The application uses these classes, and the runtime behind the scenes makes all the right magic happen (using Runtime-Callable Wrappers).
These interops are normally generated by a Microsoft tool called TlbImp, which works from a type library (TLB) that is produced from IDL compiled by the MIDL compiler. Unfortunately, many of the interfaces and methods used by FieldWorks are too complicated for MIDL/TLB, so SIL created a custom tool called IDLImp that compiles IDL into C# source that is then compiled with the normal C# compiler (Microsoft or Mono) to produce an interop DLL.
We were fairly sure that the interops that IDLImp was producing were not 100% compatible with Mono. Perhaps Mono was interpreting the .Net spec differently from Microsoft? More strictly, perhaps?
To find out, Tom and Brent took simple interops generated by both TlbImp and IDLImp and compared them. After a lot of detective work, they found that the TlbImp-produced interops had some extra attributes in them, and after adding these attributes by hand to the results produced by IDLImp, they were able to run our problem code successfully, without a crash.
This is a huge breakthrough! We have been roadblocked by this problem since before Christmas, and have had to work on other things pending a solution. We had lots of good things lined up ready to go, as soon as we could solve the COM problem. Well, now we can proceed at last. We still need to tweak IDLImp to produce the extra attributes in the interops, but that should be fairly easy.
Watch this space for further developments!