Instantiating managed COM object in C# - c#

I have written several pure .NET DirectShow filters (they are transform filters) and registered them via regasm. GraphStudioNext has no problems using them.
My problem is when my C# app tries to use the filters -- I have to get .NET to instantiate the COM object as a COM object and not a managed dotnet object. This is because I've implemented a filter selection utility (like GraphStudioNext's insert filter from a list feature) and I can't add a reference to the assembly at compile time -- someone could write a custom .NET DirectShow filter with their own ComImport'ed IBaseFilter. This will cause problems when my code tries to cast the type to IBaseFilter even though their IBaseFilter and my IBaseFilter share the same Guid. As a COM object, this would be no problem. As a .NET object, they're actually different types.
Say one inteded to write GraphStudioNext in C# and have it work with pure .NET DirectShow filters -- is this even possible?

A good question. I dealt with a somewhat similar problem here. Indeed, [ComImport] interface type equivalency doesn't work when you deal with a native .NET object directly. You need to hide the .NET object behind an artificial COM proxy for the COM interface equivalency to work.
In the solution to my question, I initially used ICustomQueryInterface and Marshal.CreateAggregatedObject to aggregate the .NET object, to expose it as COM object for that reason.
Later, I ended up implementing my own IUnknown runtime stub (using Marshal.GetFunctionPointerForDelegate for AddRef, Release and QueryInterface), which I used as pOuter (the controlling IUnknown) object for CreateAggregatedObject, so it didn't violate COM identity rules. That was hack-ish, but it solved the problem for me.

If the filter is registered in the system and you know the CLSID of it, then you can use:
Type filterType = Type.GetTypeFromCLSID(filterClsid);
var filter = (IBaseFilter)Activator.CreateInstance(filterType);
If the filter is not registered in the system, but you know the dll-location and the CLSID, you can do it like in C++. You need some P/Invokes for it! Call LoadLibraryEx and then get the IClassFactory. With this you can IClassFactory::CreateInstance of your filter.
I know this works, because we have done it and we are only using this method to work with custom directshow filters.

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.

Getting interface methods from a dynamically loaded class in .NET

I've got a .dll library I'm writing that interfaces with a proprietary COM assembly. My goal is to publish my work online once it's built, however I need to remove the COM assembly as a project reference to avoid distribution of this proprietary dll. So what I'm trying to be able to do is dynamically load the assembly at runtime, and invoke methods where I need them. Traditionally I've used object reflection for unknown types, however this can get slow at times, and involves several ugly instanciations. In .NET 4.0 is there a way to cleanly get all the methods and toss them into a dynamic class/interface at runtime?
I'm currently getting the object like this:
Type myClassType = Type.GetTypeFromProgID("MyClass.Myclass.1");
object classObj = Activator.CreateInstance(myClassType);
I thought I'd be able to use Type.GetMethods(), however it only returns the generic ones (Equals, ToString, GetLifetime..., etc.). I know the class uses an interface, so I tried looking into dynamically loading the interface also. That led me to Reflection.Emit, and the Microsoft.Xrm.Sdk, which I am failing to understand so far.
If there's a way for me to invoke methods without needing to throw a bunch of BindingFlags every few lines, I'd greatly appreciate a nudge in the right direction
I do have the GUID for both the Class and the Interface if that helps at all.
If I were at your situation(and if i have understand the problem correctly):
I would separate the Interface,s library (DLL) from implementation library(DLL)
Then the implementation library would be loaded dynamically and my main source code that is
referenced to Interface library would be complied
Type myClassType = Type.GetTypeFromProgID("MyClass.Myclass.1");
myClassIntrface classObj =
Activator.CreateInstance(myClassType) as myClassIntrface;
classObj.CallSomeInterfaceMethod();
hope this will be useful pal.

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.

COM object accessing problem in C#

I am having a hard time figuring out what I'm doing wrong, so I thought I would ask this at SO. I am trying to automate a measurement task (Qualcomm QXDM), hence would like to access the COM interface exposed by a measurement tool. I wrote the following python code with works perfectly:
from comtypes.client import CreateObject
QXDM = CreateObject("QXDM.Application")
IQXDM2 = QXDM.GetIQXDM2
...
Now, I'm trying to rewrite this is C# because of some specific requirements I have. Here's what I tried:
using QXDM;
QXDM2Class IQXDM = new QXDM2Class();
But when I try to run this, I get:
Retrieving the COM class factory for component with CLSID {6777AAE0-D9D2-4EA7-996B-0EECC68F97D8} failed due to the following error: 80040154.
What am I doing wrong? I can see all the methods and interfaces provided by QXDM in the object browser in Visual Studio.
Edit: Seems like late binding is the only way to do this as Hans suggested. I modified the code to the following:
Type QXDM = Type.GetTypeFromProgID("QXDM.Application");
Object QXDMObject = Activator.CreateInstance(QXDM);
This works. The only trouble is that I need to know what methods and classes are exposed by QXDM, which I think I could figure out using the object browser. Thanks all!
Your code just isn't the same. In the Python code you are clearly using the common "Application" object. In many automation object models, that's the object from which you create other ones. Like IQXDM2 from the GetIQXDM2() method.
Your C# code seems to be trying to create the class that implements IQXDM2 directly. Cannot work, you have to go through the Application interface. It's just like the error message says, there's no "class factory" for that object, the Application interface creates it. Whatever it is called, it is almost always has "application" in the name. Use Object Browser on the interop reference to have a look-see. Look for the one that has the GetIQXDM2 method.
If you don't see anything resembling it then you may have added the wrong DLL. Look in the registry for the name of the right one. Start Regedit.exe and look at HKCR\QXDM.Application. You'll find a CLSID key with a guid. Then look at HKCR\Clsid\{guid} where {guid} is the guid you found. The InprocServer32 key has the DLL name. An out-of-process server uses the LocalServer32 key.
If that doesn't pan out then maybe the COM server was only meant to be used by scripting languages. Very unusual but it can happen. In which case you'll have to use it late-bound in your C# code. That's only easy to do with the C# 4.0 dynamic keyword or VB.NET
It could be the fact that the DLL are dependent on other DLL's.. Debug with ProcExp (http://www.sysinternals.com/) might give some light
I think the COM objects are registered OK, or your Python code would fail and you would not see them on the machine. If this is the this case, your problem is accessing the COM objects from C#. Try the approach specified here.
If the library is already registered,
you can perform the following steps to
have Visual Studio generate an interop
assembly for you
HRESULT 0x80040154 means that the COM class is not registered. Try running regsvr32 on the COM dll.
It could be that you are building for 64 bit. Check your platform target. Make sure it's 32 bit.

Categories

Resources