Sending large data over COM interface - c#

This is the first time I am implementing C# COM Interface with Perl. I would appreciate if somebody could help me to understand how a data of key value pairs be passed over the COM interface:
Is it possible to pass Hash?
or alternatively an array or array.
Another related doubt, Is it possible to pass object over COM interface?
If so, what about array of objects?

Hashes aren't supported over COM, but SAFEARRAYs are. Safearrays can be nested, so you could pass an array of 2-element arrays.
While Objects per se can't be passed across COM, interfaces can be. (COM is language neutral; passing a C++ object to a C# or Perl runtime isn't going to work. COM interfaces have a common implementation across languages, and so can be passed around.) Safearrays support arrays of interfaces, as well.

Related

Passing List<String> from C# to native COM interface

I'm doing some prototyping, plugging into a big legacy C++ application. I'm using C# to do this as a proof of concept (eventually I will write the library in C++). I've setup a COM interface between my C++ application and a .net class library and am able to pass strings and ints between. They get automatically marshalled as appropriate (e.g. a managed string goes to BSTR*).
I now have added a new method to my COM interface which returns a List<String>. I figured the method type generated would return an array of BSTR* (BSTR**) and a count a SAFEARRAY, however when I look at the IDL (using oleview), this interface method doesn't even appear. I'm guessing the COM framework isn't sure what a List<String> looks like, so what are my options here? Just using string[]?
I'm not using C++/CX, and I cannot.
Thanks

What is Type.GUID and how does it relate to Type.Equals()?

I came across some interesting behavior while trying to compare an instance of System.RuntimeType with a generic type TOut:
Type runtimeT = methodInfo.ReturnType; // get RuntimeType using reflection
Type genericT = typeof(TOut);
// This condition fails because runtimeT doesn't
// seem to include an assembly qualified name
if(runtimeT.Equals(genericT)) { ... }
Here is my evidence:
Disclaimer: I don't know precisely what a GUID is in the context of the CLR / type-system, except of course that the acronym stands for global unique identifier. Perhaps the name is misleading me.
Assumption: I'm assuming here that aType GUID uniquely identifies the fully qualified type, including theAssemblyQualifiedName that's missing from factoryInfo.ReturnType in the screenshot (the null value.)
Is my assumption wrong?
Yes: What does type GUID truly represent, and how is it used?
No: Why wouldn't Equals() be implemented by comparing GUID?
To expand a bit upon Jared's (entirely correct) answer:
In the COM world every interface is identified by a globally unique identifier. There is no such thing as "changing" an interface in COM; interfaces are required to be the same forever. Instead, you create a new interface and give it a new GUID. Any two interfaces that differ are required to have different GUIDs. Interface equality is defined as GUID equality in COM.
In the .NET world, type equality is more complicated. A type is associated with a particular assembly, for one thing. But not just that! If you load the same assembly twice (say, once by its assembly name and once by its disk location) and ask the two assemblies for "the same" type, you will get two different type objects and they will not compare as equal even though obviously they have the same GUID.
Clearly this is a major point of departure; .NET and COM are deeply incompatible in this regard. What happens when interop must occur? Somehow COM and .NET have got to agree on some rules for how types are compared for equality when both are in play in the same process. (Because .NET is calling COM code, or vice versa.)
Thus what you can do in .NET is say "this type is associated with this GUID". When COM rules apply, the COM code will compare two types for equality by comparing GUIDs, because that's what equality means in the COM world.
In .NET, types are compared for equality using the usual rules for .NET.
This then presents a significant potential problem in a common scenario. Suppose you have written a .NET program which interoperates with a large, complex COM library. Just to pick a completely non-random example, suppose you've written a managed extension to Word, which has an absolutely enormous COM "surface area". This surface area is exposed to the .NET world via a Primary Interop Assembly, which contains "dummy" types that have all the same GUIDs as the corersponding interfaces in the COM world. The .NET code can then be written to talk to the COM layer via the "dummy" objects, which look to COM like objects of the appropriate interface type, and look to .NET code to be objects of the appropriate .NET type.
So that works just fine. And then you go to ship your .NET library to customers and you realize Word does not ship the PIA to customers automatically. Rather, you are required to ship their PIA. Which is enormous.
Thus was born the "no PIA" feature of C# 4. In C# 4 you can generate a Word extension that makes an internal copy of only the portions of the word PIA that it actually uses. Which is typically much smaller. You can then redistribute your extension library without redistributing the large PIA.
But this immediately presents a problem. Suppose there are two such libraries, and they want to communicate with each other using the interface types that are common to both, in the PIA? From the .NET perspective, types are per-assembly; the copies of the PIA types in each library are the same from COM's point of view, but different from .NET's point of view.
Therefore we added a special feature in the v4 CLR. In that situation, the two types in the two different assemblies (and the PIA type, if it is present!) are unified by the CLR and are treated as equal by GUID, matching the COM behaviour.
The details of course are much more complex than that simple sketch. My point is simply that you are opening an enormous can of worms here; how GUIDs interact with type equality is a deep and tricky subject that few people understand fully.
One reason that Type.GUID isn't used as the comparison for Equals is that it's user controllable item. For example i can dictate the GUID of my interface by doing the following
[Guid("2bfd006d-94b9-43af-843f-5b32f7567086")]
interface IFoo { ... }
This is necessary in order to produce interfaces for COM interop. If Equals relied on the GUID being unique to a type then a given developer could wreak havoc on the system by giving their type the same GUID as say string, int, etc ...
You shouldn't really rely on System.Type's GUID property for Type comparison. Especially in inter-process communication (WCF, Remoting) , the Guid may not be the same (unless it's manually specified as in JaredPar's example).
Internally, Type.Equals uses a RuntimeTypeHandle for equality comparison.
I'm not sure why your equality comparison above is failing. It shouldn't. In the very simple example below, equal returns true.
static void Main(string[] args)
{
Test<object>();
}
static object Test<T>()
{
var currentMethod = ((MethodInfo) MethodBase.GetCurrentMethod());
var oType = currentMethod.ReturnType;
var genericType = typeof (T);
var equal = oType.Equals(genericType); // result is true.
return null;
}
My random shot in the dark guess is that you're using Entity Framework with Proxy Creation Enabled? In which case, generic parameter T of IEntitySet is a dynamically generated type that Entity Framework has created for you... If this is the case, you should get the desired result by comparing the generic arguments individually:
A GUID is randomly generated sequence of bytes (16 by default) that is semi-guaranteed to never be repeated - not across computers or time. Semi-guaranteed because the possibility to repeat does exist but it's so minuscule it is not considered.
Because of this, most programmers use GUIDs when they need to provide an ID to something where they worry about the ID having a collision against another ID that may end up existing in the same realm (IDs of programs running, or of table rows or a million other things)
But in short, you can think of a GUID as a random-ish number that represents an ID, is 16 bytes long and won't ever be generated twice.

What is the best way to deal with kludgy interface hierarchies (MSHTML)?

I'm using the MSHTML API from C# 4.0 and the logistics of running code are not a problem. Writing the code, however, is a pain due to the way that MSHTML and/or COM interfaces are designed. Specifically, there is no interface hierarchy when there should be one. For example, IHTMLDocument7 does not extend IHTMLDocument6, which doesn't extend IHTMLDocument5, and so on (IHTMLDocument2 does extend IHTMLDocument, though).
To further confuse matters there is an HTMLDocument interface that extends DispHTMLDocument (which has all of the methods of the IHTMLDocument* interfaces) and HTMLDocumentEvents_Event (which provides some, but not all, events). To add to the mess, HTMLDocumentClass is a coclass that implements all of the aforementioned interfaces and then some, such as IDocumentSelector and HTMLDocumentEvents4_Event.
I'd really like to be able to work with the API of HTMLDocumentClass, but trying to cast to it gave me:
System.InvalidCastException: Unable to
cast COM object of type
'mshtml.HTMLDocumentClass' to class
type 'mshtml.HTMLDocumentClass'.
Instances of types that represent COM
components cannot be cast to different
types that represent COM components;
however they can be cast to interfaces
as long as the underlying COM
component supports QueryInterface
calls for the IID of the interface.
In addition, some of the interfaces don't have an associated coclass; e.g., there are IHTMLElement* interfaces but no HTMLElement interface nor a HTMLElementClass class. Overall, I am finding it difficult to program to an interface.
Are there good techniques for wrangling with this interface train wreck, or should I give up IntelliSense and use dynamic everywhere? I considered writing wrapper classes that implemented all of the interfaces, but there are so many MSHTML interfaces and each of them has a ton of members so a practical solution has to be automated.
IHTMLDocument6 doesn't extend IHTMLDocument5
Even if it extends IHTMLDocument5, per COM rules, you are still supposed to QueryInterface to get IHTMLDocument5, not to use inheritance. I am glad that they did not let you wonder how you can QI for an interface that is already implemented by the wrapper class as a side effect of inheritance.
I suggest you to not use any of the wrapper classes and switch to backward compatible interfaces when you control the objects. The COM wrapper CLR generated for IE looks like a mshtml.HTMLDocumentClass class from a different assembly, based on the error message.
In COM programming you would see the factory pattern quite often. For the html element object, the factory method is IHTMLDocument2.createElement. Usually you can not create the object on your own if the author choose to use this pattern.
Visual Studio would automatically reference the PIA if one exists, otherwise it uses tlbexp.exe to generate interop assembly prefixed with "Interop". However most of time you would be using a handful interfaces in the PIA, so you can write your own interop types (or copy from Google Code Search) and get ride of this big assembly.

Marshal a list of objects from VB6 to C#

I have a development which requires the passing of objects between a VB6 application and a C# class library. The objects are defined in the C# class library and are used as parameters for methods exposed by other classes in the same library. The objects all contain simple string/numeric properties and so marshaling has been relatively painless.
We now have a requirement to pass an object which contains a list of other objects. If I was coding this in VB6 I might have a class containing a collection as a member variable. In C# I might have a class with a List member variable.
Is it possible to construct a C# class in such a way that the VB6 application could populate this inner list and marshal it successfully? I don't have a lot of experience here but I would guess Id have to use an array of Object types.
Options are more limited through COM than what you have in C#:
You can't use generics (COM does not have support for this, and TLBEXP will leave them out)
There is the olden ArrayList class. Or an array.
The COM interop layer will automatically generate a COM enumerator for a C# class that implements IEnumerable (the non-generic version), you can iterate it on the VB6 side with For Each.
Similarly, it generates an IEnumerable for a COM class that implements an COM enumerator. You can use foreach in C# code to enumerate a VB6 Collection. Choose between them depending on who creates the collection.

Is it possible to read/write classes/structs written in C# from VB6?

I just wonder if that is possible.
I know simple types can be read through com interface. Does anyone have experience with complex types as structs and classes?
Simple types are passed through COM as Variants. Strings, ints, floats, IUnknown interfaces, and arrays of all of these can be carried in Variants.
C# and other .NET managed language types can be exposed through COM to unmanaged code, but COM will limit your options to basically interfaces. You should define interfaces in your managed code and tag them with the ComVisible attribute so that they can be seen by COM. Implement those interfaces on your classes or structures and you're good to go.
I forget offhand how to instantiate a managed class from unmanaged code via COM, but search for .NET COM interop and it should be in there somewhere.

Categories