检索传出dispinterface成员的DISPID

时间:2014-11-19 17:23:11

标签: winapi com automation typelib idispatch

我坚持这个。

给出三个变量:

  • IDispatch*到可连接对象
  • 该对象上的传出调度接口的IID(DIID)
  • 由dispinterface
  • 定义的成员的名称

如何将名称解析为DISPID?

  • pDispatch->GetIDsOfNames(...)返回DISP_E_UNKNOWNNAME,正如我所料(可连接对象未实现传出接口)
  • 我需要支持0个客户端已连接到传出接口的场景,因此我无法枚举现有的连接点,以便在其中一个上调用GetIDsOfNames(我甚至不确定这个会工作)
  • 为了执行手动反射,我需要调度接口ITypeInfo。我可以从coclass的ITypeInfo得到这个。但是pDispatch->GetTypeInfo(0, ...)会返回ITypeInfo实现的IDispatch(根据文档),而不是coclass的ITypeInfo。 (并且此对象的ITypeInfo实现没有公开其他IDispatch。)

1 个答案:

答案 0 :(得分:0)

如果对象是“非常标准”,那么它应该是可能的。

从object / IDispatch接口,您应该能够访问TLB(类型库)。从类型库中,您应该能够浏览所有coclass,并获得这些coclass实现的接口。您需要进入具有IID的界面,浏览该成员并获得您感兴趣的成员。

在许多情况下,这是行不通的。这是我提出的一个控件示例,它与shell对象一起使用。我用C#编写它是因为它更容易,但是对于一个体面的语言来说,没有什么是你无法做到的。我使用了一个旧的TLBINF32.DLL com实用程序库(不幸的是只有x86)我在这里谈到这个问题的答案:How to read COM TypeLib with C# or C++?

    static void Main(string[] args)
    {
        // create a sample object every one has
        object o = Activator.CreateInstance(Type.GetTypeFromProgID("shell.application")); // for example
        TLIApplication app = new TLIApplication();

        // not sure, but I believe in pure COM it's calling IDispatch::GetTypeInfo & ITypeInfo::GetContainingTypeLib 
        TypeLibInfo tli = app.InterfaceInfoFromObject(o).Parent;

        // this is the guid for DShellFolderViewEvents
        int dispid = GetDispId(tli, new Guid("{62112AA2-EBE4-11CF-A5FB-0020AFE7292D}"), "SelectionChanged");
        Console.WriteLine("dispid:" + dispid); // should display 200
    }

    public static int GetDispId(TypeLibInfo tlb, Guid diid, string memberName)
    {
        // browse all coclasses
        // in pure COM this is ITypeLib::GetTypeInfo
        foreach (CoClassInfo ti in tlb.CoClasses)
        {
            // browse all interfaces in those coclasses
            // in pure COM this is ITypeInfo::GetRefTypeOfImplType 
            foreach (InterfaceInfo itf in ti.Interfaces)
            {
                // only select [source] interfaces (events)
                // this test is optional since the diid is unique
                // in pure COM this is ITypeInfo::GetImplTypeFlags
                if (((ImplTypeFlags)itf.AttributeMask & ImplTypeFlags.IMPLTYPEFLAG_FSOURCE) != ImplTypeFlags.IMPLTYPEFLAG_FSOURCE)
                    continue;

                if (new Guid(itf.GUID) == diid)
                {
                    // in pure COM this is ITypeInfo::GetTypeAttr & ITypeInfo::GetFuncDesc
                    foreach (MemberInfo mi in itf.Members)
                    {
                        if (mi.Name == memberName)
                            return mi.MemberId;
                    }
                }
            }
        }
        return -1;
    }