Get property names via reflection of a COM object - c#

How can I read out all property names via reflection of an COM Object in C#?
I know how to get the property if I know the name.
comObject.GetType().InvokeMember("PropertyName", System.Reflection.BindingFlags.GetProperty, null, comObject, null);
but what is when I want to dump all properties?
PropertyInfo[] properties = t.GetProperties();
This way didn't work with Com-Objects. If I do a GetMembers() I get these Members:
Name: GetLifetimeService
Name: InitializeLifetimeService
Name: CreateObjRef
Name: ToString
Name: Equals
Name: GetHashCode
Name: GetType
regards Chris

You got the members of the __ComObject class, the underlying .NET class for an RCW.
COM has a wee bit support for reflection, as long as the COM coclass implements IDispatch, the Automation interface. Not unusual, it is the interface that scripting languages use to make calls. IDispatch.GetIDsOfNames() is always implemented, but you have to know the name of the member up front. IDispatch.GetTypeInfo() gives access to the type library for the coclass, but isn't always implemented. Translation of type library info to metadata is an imperfect art, the core reason why .NET wants you to do this upfront with Tlbimp.exe. If you want to pursue a runtime approach then you'll probably benefit from the source for the managed version of Tlbimp, available here.
Doing this up front at build time is always best, you do so by adding a reference to the type library (usually embedded in the executable file) or by running Tlbimp.exe yourself. Now you got a .NET interop wrapper class that has all of the members of the underlying COM coclass and interfaces. At which point you probably don't need reflection anymore :)

I've just published a CodeProject article about how to do Reflection with IDispatch-based COM objects. The article provides a small C# DispatchUtility helper class that's easy to include in other projects. Internally, it uses a custom declaration of IDispatch and .NET's TypeToTypeInfoMarshaler to convert IDispatch's ITypeInfo into a rich .NET Type instance.
In your example, you could call DispatchUtility.GetType(comObject, true) to get back a .NET Type instance, which you could then call GetProperties or GetMembers on.
I've also provided a version of the DispatchUtility source code on StackOverflow in a response to How to enumerate members of COM object in C#?

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 :)

Instantiating managed COM object in 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.

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.

Reflection in C# not working with COM (and C++)

First of all: I'm total beginner.in COM.
I'm working in team on big project. The server part is written in C++. The client side is written in C#. They communicate through COM.
Now - I have interface IA in C#. And I have object o, whose type is class A (implements IA in C++ - it is somehow trasfered via COM). I want to use reflection to get all properties of that type, but it's not working properly. It returns just those properties, which I have used in my code.
Here is the Reflection code that retrieves the properties:
Type[] ifaces = typeof(A).GetIterfaces();
foreach (Type iface in ifaces)
{
foreach (PropertyInfo info in iface.GetProperties())
{
// it takes only those properties, I have used in C# code
}
}
First I thought it's not working because of COM. But it's weird, that it gives me all properties, which I mention in code. And all stuff around COM should be written correctly, because it's working for a long time (before I got to this project).
This might help you: Using Reflection with COM Interop
This would help only if you know possible options for the property name, if you have no idea but want to list them, you might have to dive into the tlb file. Good example on how to load a typelib and get the AssemblyBuilder class you can find here. AssemblyBuilder.GetExportedTypes method should return all types defined in TLB, and then you can use reflection on those types.
I have been struggling with this, so if you get it working, maybe you could post a solution here.
The problem was in Embed interop types. I switched from True to False and it's working.

COM to .NET Interoperability

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.

Categories

Resources