Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding Out what Interfaces are Queryable for a COM Object?

Tags:

c#

com

I am working with ESRI's ArcObjects COM Library, i am trying really hard to figure out what type "selected" should be:

IMxDocument doc = m_application.Document as IMxDocument;
object selected = doc.SelectedItem;

SelectedItem returns a comobject (Not Null), generally representing the data type that is currently selected. However i do not have the faintest idea what type i am supposed to cast it to. When i debug it, i don't really see anything useful:

http://imgur.com/Yfo6G

(watch debug after the value is set)

ESRI's ArcObjects library is huge, and is pretty poorly documented, i simply cannot figure it out. I even went so far as to manually check about 50 or so interfaces that i thought it should be.

Does anyone have any ideas how i can figure this out?

EDIT To clarify their documentation is absolutely no help, neither is their forums.

like image 495
UberJumper Avatar asked Dec 02 '10 18:12

UberJumper


2 Answers

After reading your question, the answers, and the comments, you may have to write a utility to find the answer by brute force.

Use reflection to scrape a list of interfaces out of your interop assembly, then simply loop over this list and see if your object supports each interface in turn.

Update

Some sample code:

    object unknown = //your com object...

    Type someComObjectType = typeof(ExampleTypeInInteropAssembly);

    Assembly interopAssembly = someComObjectType.Assembly;

    Func<Type, bool> implementsInterface = iface =>
    {
        try
        {
            Marshal.GetComInterfaceForObject(unknown, iface);
            return true;
        }
        catch (InvalidCastException)
        {
            return false;
        }
    };

    List<Type> supportedInterfaces = interopAssembly.
        GetTypes().
        Where(t => t.IsInterface).
        Where(implementsInterface).
        ToList();

    if (supportedInterfaces.Count > 0)
    {
        supportedInterfaces.ForEach(Console.WriteLine);
    }
    else
    {
        Console.WriteLine("No supported interfaces found :(");
    }
like image 82
Tim Lloyd Avatar answered Sep 19 '22 10:09

Tim Lloyd


I'm not familiar with that library, but I can give some suggestions. Once you look at the problem from the point of view of COM you'll see that there is no simple answer.

(Do keep in mind that that in COM all objects are just objects, and that the only requirement is that it must support IUNKNOWN (and possibly other interfaces). So the answer to the question "what type of object it is" can often have more than one answer.)

The important thing to remember is that in COM the list of interfaces for an object is not defined in any sort of metadata like it is in .NET (except that a library usually provides an optional type library as a form of documentation for development tools -- more on that in a minute).

The list of interfaces is officially defined only by the results of calling IUNKNOWN's QueryInterface() method -- that is, it's defined entirely by the result of executing code.

Some times the list might be hard-coded. Often, the list might not be known until runtime, and it might not even be known until somebody asks. The only rule is that the list of interfaces needs to be stable and what I call sensible: the list cannot change over time for a given object instance; it must support IUNKNOWN, which sometimes people forget; if it supports a derived interface, it must support its base; and a couple of other I'm sure I'm forgetting.

That last point is crucial to your problem: COM doesn't know a priori what interfaces are supported by any object. The .NET runtime doesn't know either -- not from COM anyway. The only way for .NET to know would be if the Type Library for the object says that the object returned is of a specific interface. Lacking that, all you have is an IUNKNOWN pointer and you have to ask for specific interfaces via code and see if you get an answer other than NULL.

Since the type of the SelectedItem propery is object, it means that the type library simply says "the return type is an interface pointer of type IUNKNOWN" (it might be IDISPATCH, but the principle stands). The exact type obviously depends on runtime circumstances -- "what happens to be selected right now".

(In .NET, the return type is actually System.__ComObject because you don't get a naked interface pointer but a COM callable wrapper which a .NET based proxy to the object)

You are at the mercy of the (poor?) documentation of the library to get a clue on what kinds of interfaces the returned object might support. Lacking that, code like Chibacity's might get you a partial list as well (I have not reviewed that code). Ultimately, you probably want to use that code to get a list of candidate interfaces during debugging.

Once you know a few possibilities that interest you, you can save yourself some typing trouble by just using the C# as operator (which causes the COM callable wrapper to issue the corresponding COM spells against the native object).

like image 20
Euro Micelli Avatar answered Sep 20 '22 10:09

Euro Micelli