COM to .NET Interoperability - c#

If you want to use a COM type in your C# code, the process is straight forward, right? You just need to use the type library importer and that's fine, but what if you don't have one and you can't take a look at the IDL file? You just have the COM DLL server.
As an example, try using the IActiveDesktop interface.
What's the approch used to solve this kind of problem?

There are two kinds of COM interfaces. The one you are familiar with are the ones that restrict themselves to a subset of the COM spec known as "OLE Automation". Also known as ActiveX before that term became associated with security disasters.
Automation compatible interfaces are easy to use from just about any language. They typically inherit from IDispatch, allowing them to be used from scripting languages. And limit themselves to using only automation compatible types for their method arguments. The simple stuff, comparable to the .NET value types, BSTR for strings, SAFEARRAY for arrays, VARIANT for untyped arguments, quite similar to .NET's System.Object.
Another feature they support well is type libraries, the equivalent of .NET metadata. Used by a compiler to know how to call the interface methods. The IDE uses a type library to automatically generate the interop library so you can directly create the wrapper class and call the methods from .NET code.
Well, that's the good news. The bad news is that there are lots of COM interfaces around that do not use the Automation restrictions. They typically inherit from IUnknown and use function arguments that don't marshal well. Like structures. One very large and visible component in Windows that is like this is the shell. Windows Explorer.
That's where IActiveDesktop fits in as well, it is a shell interface and inherits from IUnknown. It is declared in the ShlObj.h SDK header file, there is not even a IDL file for it. And consequently no way to get a type library with its definition. It uses incompatible argument types, like LPCWSTR (a raw pointer to a string) instead of BSTR. And structure pointers like LPCCOMPONENT and LPWALLPAPEROPT. The CLR interop support is powerless to marshal that properly.
Using the interface in C# is technically not impossible, but you have to redeclare the interface. Very carefully, getting it wrong is very easy to do. The fact that source code that already does this is very hard to find is a hint how difficult it is. This squarely falls in the 'not impossible, but what sane programmer wants to maintain code like this' category. The shell is the domain of unmanaged C++ code. And a crew of hardy programmers, because debugging shell extensions is quite painful.

Related

Can a COM/.NET interop assembly be used with a newer version of the COM component?

I call into a COM component from a C# project, via an interop assembly that I generate from the COM DLL. The COM interface has DispIds defined and I have verified that these appear in the generated interop assembly.
Empirically, if I upgrade the COM component to a newer version, the interop calls go horribly wrong (as if it's calling the wrong COM methods).
Is this expected, i.e. that the interop assembly is tightly bound to the specific version of the COM interface that it was generated for? I had naively assumed that as long as the DispIds and function prototypes matched up in the new COM component, which they do, it would all work OK.
Is there a way of telling the CLR to use the DispIds when calling into the COM component via the interop assembly, i.e. a late binding of sorts? (I know it is possible to use late binding using reflection-style C# code, but this would be less convenient than an interop assembly.)
I found Brian Long's article .NET Interoperability: COM Interop:
The most common requirement will be to use early binding to get compile-time type checking and direct (well, as direct as it gets) vtable calls to the COM objects. The [interop assembly] example above took this approach.
An interop assembly resulting in "direct vtable calls" sounds like it would not work with a new version of the interface (unless, perhaps, new methods were only added to the end of the interface, i.e. to the end of the vtable?).
Perhaps someone can corroborate or provide a more complete answer?
DispIds are only used when the client programmer uses late binding. If that's what you want him to do then you have to enforce it. That's very easy to do, apply the [InterfaceType(ComInterfaceType.InterfaceIsDispatch)] attribute on the interface. If you didn't write an interface but only a class then give it the [ClassInterface(ClassInterfceType.AutoDispatch)] attribute.
Any attempt by the client programmer to use the dangerous early binding will now fail, he must write late-bound code. Don't expect a thank-you note.
The only other way is to remove the [Guid] attribute you now use. It is very dangerous, let the CLR auto-generate the guid so it will automatically be different when you change the interface. And the client programmer gets a decent E_NOINTERFACE error instead of calling the completely wrong method. Well, don't expect a thank-you note :)

Why registering COM interfaces?

I've used COM for some years now but I keep learning new (and strange) things.
Recently I've realized that COM interfaces didn't had to be registered in the registry for components implementing them to work.
I've come to this conclusion after analysing the registry of a workstation where COM DLLs (implemented in .Net/C#) were registered with .reg files created by RegAsm because the user was not an administrator. And RegAsm only generates registry keys for COM classes and not interfaces.
If that's true my guess is that interfaces are important for early binding and have only to be present in TLB files. On the contrary registering implementations (classes) is essential because they are backed by physical code on the file-system that need to be referenced.
1) So am I crazy, missing something, or interfaces can be omitted?
2) If they can be omitted what are the consequences if any?
There are a lot things that you can't do without the interface being registered. Many of the features of COM -- marshaling, proxying, asynchronous calling -- have standard implementations that prevent you from having to roll this stuff yourself. For example, CoMarshalInterface is a standard way of taking any COM object interface and marshaling that interface into a stream so that it can be unmarshaled in another thread, process or machine. The interface information is critical in this -- without the interface metadata, the standard COM implementations of things like this won't work, as the infrastructure simply doesn't know enough about your interfaces to do what it needs to do in a generic way that works for all COM objects.
Additionally, while most automation clients (like VBA, C# and C++) can reference a type library file directly for purposes of early-binding, there are still limitations. For example, suppose you're working with a type library that contains some classes that implement interfaces from a different type library, or maybe the interfaces in the first type library accept parameters or return values that are defined by interfaces/enums/etc in another type library. In order for an automation client to work with these interfaces which contain cross-references, the cross-referenced type library must be discoverable somehow. Registration is the way this is accomplished.
Worth noting: In my experience, pretty much everything that works when a COM object is registered machine-wide (registered in HKLM) works exactly the same when registered per-user (in HKCU). This often makes COM registration more palatable in situations where machine-wide registration can't be performed (e.g. the user is not an admin). However, there are some significant gotchas, most notably https://techcommunity.microsoft.com/t5/Windows-Blog-Archive/Per-User-COM-Registrations-and-Elevated-Processes-with-UAC-on/ba-p/228531
Pretty vague, not sure I could read all the words between the bold ones. There is in general more than one way to skin this cat. COM requires using a class factory to get an object created, the generic work-horse one is CoCreateInstance(). CreateObject() is popular in scripting environments. You give it a number and it spits an interface pointer back. With the COM runtime taking care of the job to locate the executable file that contains the coclass, loading it and finding the proper class factory implementation.
Finding the executable is the tricky part, this is commonly done by info in the registry. Entered there when the component was registered. Not exclusively, a manifest can also be the source of this info. It needs to be embedded in the client app, one reason it is not a universal solution. More modern is the package manifest in a Windows Store/Phone/Universal application. Required, only very privileged components can still use the registry to let themselves be found. Microsoft components.
A completely different tack is having custom class factories. The way it is done in DirectX for example, it doesn't depend on the registry at all. You call CreateDevice() instead. Still calling this COM is a bit of a stretch, it is a more general technique called interface-based programming.
This all applies to objects, interfaces are different. You call IUnknown::QueryInterface() to obtain an interface pointer. No registration required, it is the coclass that handles it.
Nevertheless, you'll find lots and lots of registered interfaces with Regedit.exe in the HKLM\Software\Classes\Interface registry key. They take care of another COM detail, if the component does not live in the same machine or same process or the same thread as the client code then extra work must be done to get the call serialized across the machine/process/thread boundary. Same kind of thing that happens in .NET Remoting, it requires a proxy. An object that also implements the same interface but doesn't execute the method directly, passing the arguments to the stub instead so it can make the call.
Simple to do in .NET, Reflection makes it very easy. Not simple in COM, an extra component is required that knows how to serialize the arguments into an interop packet. And get the return value back the same way. Proxy/stubs are normally automatically built from the IDL. Or very common in .NET since it doesn't use IDL, you use the marshaller that digs out method details from the type library. A mechanism that's highly comparable to .NET Reflection, the type library plays the exact same role as .NET metadata does.
The ProxyStubClsId32 registry key inside the Interface key contains the CLSID of that component. You'll very commonly find {00000320-0000-0000-C000-000000000046} there, that's the system provided marshaller that uses the type library.
Regasm doesn't write the interface keys, it sets the ThreadingModel key for a .NET [ComVisible] class to "Both". So that the methods can be called both from an STA as well as an MTA thread without having to be marshaled. That's very optimistic and very rarely tested, writing thread-safe .NET code isn't that easy.
Regarding your first question, if the interface is not supposed to be used across COM contexts, or if the interface derives from IDispatch and you only use late-binding, you don't need to register it.
However, if you use early-binding, or if the interface is supposed to be used across COM contexts, you need to register it.
Just registering an interface doesn't enable marshaling, all argument types and return types must be marshalable too, i.e. not HANDLE or alike.
Regarding your second question, my hope is that you can answer yourself after reading the answer thus far. If not,
if you don't register an interface, you can't use it directly across COM contexts. If it derives from some registered interface, you can use that interface, such as the case of IDispatch-based interfaces.
However, very few interfaces are as general as IDispatch, so for any other base interface, you won't be able to use your derived interface's new methods.
In type libraries, if you don't register event dispinterfaces, then development tools (typically IDEs) won't be able to show you which events can be fired, or any event at all. The only other option is to implement the dispinterfaces by hand, if your programming language has that option, which requires documentation equivalent to the missing IDL in the first place.
One common extreme of this is to have all objects simply implement IDispatch and no other interface, but again this will hinder any effort a development tool might do towards method listing, code completion and/or argument choice (e.g. IntelliSense). Note that sometimes this is enough, such as when implementing a window.external object for IE's JScript, but it's a bit of lazyness when done in more general objects.
In general, if you're required very few extra effort to have interfaces registered, given you're already targeting COM, do so.

Difference between Dual interface and Dispatch only interface for C# COM automation

I am implementing a c# COM client against a C++ COM server. The COM client functions correctly when I mark the COM interface as "Dual" but it throws an InvalidCastException when I remove the "Dual" attribute.
Therefore the easy fix for me is to mark it as Dual. But from reading online, it looks like it is not the recommended approach to use for COM servers. Can anyone explain to me the significance (in layman terms) to marking an interface as dual and why it would not be recommended?
I only need it for testing purposes, and I'm using C# client (don't anticipate that I ever will use VB)
Alternatively, can anyone point me to a good walkthrough on creating a C# COM client for non-Dual interfaces (the examples on MSDN all are dual interfaces) Thanks!
When you create a COM object for public consumption, you have different options as to how you can make your interface(s) available for public consumption.
If you only want to make your COM object available to low-level programming languages (like C++, C, C#, etc.) which support things like pointers and vtables, you can just create a "custom" interface which inherits from IUnknown.
The problem with this approach is that your COM object will not be available to scripting clients (VBScript, JScript, WScript, etc.), as these clients don't understand pointers and vtables. Instead, you would implement your COM object interface as a derivation of IDispatch. IDispatch provides some methods that allow a scripting client to dynamically discover its methods and properties at runtime instead of compile time. However, this process is less efficient than using IUnknown, as the client has to make extra method calls before calling the desired COM object's method.
So, if you're only targeting low-level programming languages, you could implement your COM interfaces using "custom" interfaces that inherit from IUnknown
If you're only targeting scripting clients, you could implement your interfaces using only IDispatch.
If you want your COM object to be available to scripting languages, and you also want low-level languages to be able to call your methods in a very efficient manner, you should implement both, and this is called "Dual". Probably, Microsoft's examples are all "Dual" because they want their examples to work with both scripting and low-level languages (low-level languages can use IDispatch, but it takes more work).
For more info, I would suggest you watch the .Net Interoperability Course at PluralSight (you can sign up for a free trial subscription). The "COM" part of this course shows you how to create a non-Dual (simple IUnknown interface) as well as "Dual" interfaces.

Reading MSDN pages [duplicate]

What is the necessity for the GUID attribute? why don't just let the compiler handle this automatically?!
If the compiler handled this automatically, you'd end up with one of two situations.
A new GUID every time you compiled - since GUIDs are supposed to be published, this would fail.
Collisions - if the GUID was the same every time, based on (say) a Hash of the name, multiple projects would end up using the same GUID for different purposes.
The existing approach - an explicit GUID gives developers the power to control these as required.
These are attributes that matter a great deal to COM. Which was the predecessor of .NET and had its heyday in the nineties, before Java stole the show. .NET needed to be compatible with COM to have a chance of succeeding. Or in other words, you needed to be able to write a COM server in a .NET language that a large legacy program could use.
The [ComVisible] attribute ensures that a COM client program can see and use the IEnumerable interface. Essential to allow the client program to enumerate .NET collections.
The [Guid] attribute is crucial in COM, it identifies an interface. Which is done by a guid, not a name, to ensure that it is unique across multiple applications written by different programmers. .NET has this too, but however uses a name to make it easier on humans. "System.Collections.IEnumerable, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089".
IEnumerable<>, the generic version, doesn't have a [Guid]. Generics are not compatible with COM. It doesn't much matter these days, not much visible COM around anymore, most of it has been wrapped by friendly .NET classes. But still very core in Windows, notably in the brand-new WinRT (aka Metro, aka Modern UI, aka UWP). You don't use that directly either, making COM somewhat like the assembly language of Windows programming.
You can do it (just omit the attribute) but then the compiler will generate a new GUID on each recompile even if the interface has not changed. That's unfortunate because the users of that interface don't know about the change and will retrieve the interface by it's old GUID and will therefore fail to retrieve it.
Sometimes you want to give certain classes or modules a unique identifier that is constant and hard coded inside your source.
To read this definition you would need to look up the meaning of each of those attributes. The first, ComVisibleAttribute, is described as this:
Controls accessibility of an individual managed type or member, or of all types within an assembly, to COM.
That tells us that ComVisible is something to do with COM, and lets us specify whether a particular type is visible to COM programs. Further down on the page is a link to more details on what the attribute is for and how its used by the type library exporter.
The second, GuidAttribute, is a bit less helpful at first:
Supplies an explicit System.Guid when an automatic GUID is undesirable
but again, you have to read the rest of the way down, and you will see another mention of the type library exporter.
Putting these two together, it starts to become clear that these two attributes control how IEnumerator is processed when exported to a type library. If you don't know what a type library is, this will probably not mean much to you. If you are not using COM interop, then those attributes can safely be ignored. If you are using COM interop, you would need to know the Guid to properly access the interface from unmanaged COM code.
Microsoft puts these on every interface definition in case you need them; part of the skill in reading the MSDN pages is to recognize this type of information and know when it isn't any use to you. Now that you know what those two attributes are for, you should be able to figure out if they are relevant to you, and ignore them otherwise.

How is COM associated with C Sharp while converting VC++ code (which involves COM concepts) to C#?

I have good knowledge in C sharp and C++. But I am totally new to COM programming. I am converting some code from VC++ to C#. But VC++ code involves a lot of COM keywords like STDMETHODIMP , STDMETHODCALLTYPE, __declspec , HRESULT , and other COM Programming concepts. I didnt get what are these COM terminilogies.
But since I can understand C++, I am able to understand the logic involved in the VC++ code and converting this logic to C# implementation IGNORING the COM terminologies.
Some functions in my VC++ code are having the returning type STDMETHODIMP and they are just returning S_OK or E_FAIL etc.. How shall proceed with my conversion to C Sharp ? What should I return in my C# code for these VC++ functions which are returning S_OK E_FAIL and what return type should I use in my C# code instead of STDMETHODIMP. ?
In fact there are many such COM terminologies in my VC++ code like "skippedEntity()" "processingInstruction()" etc.. In fact this VC++ code is making use of a DLL called "msxml6.dll". And implementing the interface methods in it. So, is it ok if I IGNORE these COM Terminologies and proceed implementing the logic invloved in VC++ code to C#.
Kindly let me know same..
Since COM is an Alien concept to me, sorry if I am asking some silly doubt or meaningless doubt..
Thanks In Advance..
The uppercase identifiers are macros, they ensure that the COM interface function has the proper signature. A COM function that's compatible with automation must use the correct calling convention, __stdcall, and must return a long (an hresult) that indicates the error or success status. Additional requirements are that the COM interface must implement IUnknown and that the function argument types should restrict themselves to automation compatible types.
The COM interop support in the CLR ensures that these requirements are met. It generates a v-table for a C# interface that automatically implements IUnknown, you don't have to implement it yourself. The HRESULT return value is automatically generated, it is mapped from an Exception. Function arguments are automatically marshaled from their unmanaged type to the equivalent native type.
The argument type translation is a rather large topic and covered in any decent book about the subject (like Adam Nathan's). Suffice it to say that any automation compatible type has a corresponding managed type. The harder ones are object to VARIANT, string to BSTR and array to SAFEARRAY.
You use the [ComVisible] attribute in C# to create a COM server. Several other ones are relevant, like [Guid] and [InterfaceType]. This is well covered in any examples. You create the type library with Tlbexp.exe or, more commonly, with Regasm.exe /tlb. The latter tool is the one that's required to register the server, you cannot use Regsvr32.exe anymore.
Most of that stuff is handled automatically if you add a com-reference in your project (or import with TLBIMP).
S_OK and S_FAIL are converted to exceptions. See MSDN.

Categories

Resources