1

我坚持这个。

给定三个变量:

  • 一个IDispatch*可连接的对象
  • IID对象上的传出调度接口的 (DIID)
  • 分配接口定义的成员的名称

如何将名称解析为 DISPID?

  • pDispatch->GetIDsOfNames(...)Returns DISP_E_UNKNOWNNAME,正如我所料(传出接口不是由可连接对象实现的)
  • 我需要支持 0 个客户端尚未连接到传出接口的场景,因此我无法枚举现有连接点以调用GetIDsOfNames其中一个(我什至不确定这是否可行)
  • 为了执行手动反射,我需要 dispinterface 的ITypeInfo. 我可以从 coclass 的ITypeInfo. 但是pDispatch->GetTypeInfo(0, ...)返回ITypeInfo实现IDispatch(根据文档),而不是ITypeInfococlass。ITypeInfo(并且这个对象的实现没有暴露其他s IDispatch。)
4

1 回答 1

0

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

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

在很多情况下,这根本行不通。这是我提出的与 shell 对象一起使用的控制台示例。我用 C# 编写了它,因为它更容易,但没有什么是你不能用体面的语言做的。我使用了一个旧的 TLBINF32.DLL com 实用程序库(不幸的是只有 x86)我在我对这个问题的回答中谈到了 SO: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;
    }
于 2014-11-20T22:19:43.677 回答