dotNET 枚举COM实例的成员

        枚举COM的成员信息的方法,比较多可以从类型库(TLB)中获取,也可以从COM实例自身去获取,一般来说任何COM对象都必须实现“IDispatch”接口,而此接口规定了获取当前实例的类型信息的接口,它是编译器强制性实现的,即开发人员编写一个COM类并且正确编译,那么在编译过程中编译器会对这个COM类构建它的类型信息到库中,当然这个主要是C/C++ ATL开发中,dotNET与此类似,所以不存在这个类型信息丢失无法访问的问题(当然不排除恶意的改变了实例虚函数链表的问题)。

        本文代码仅仅只是初略的获取一个COM实例的“参数类型、返回值类型、成员备注”等几个一般性信息,所以不需要利用“ITypeInfo2”接口来获取,例如你期望在dotNET完成一个反射所需的“TypeBuilder”的实现且与COM调用与之相连,用于增强dotNET系统默认的TypeBuilder(辅助你所应用代码块的类型调用绑定),那么你并不一定需要获取很复杂的COM类型信息,记住一点获取的信息越加复杂那么效率也就越来越慢,这是一个很形象的问题,正如dotNET框架的TypeBuilder也仅仅只是涉及到了某个友元函数的参数类型与PARAMFLAG上面而已,PARAMFLAG_FOPT 标志指改参数“可空或可选”。

        ITypeInfo/ITypeInfo2接口中定义的COM的类型信息,它并不是足够直观,即定义的相关的接口与结构有些容易令人混淆,比较关键的一点就是说例如你需求获取某个成员的信息,它在定义的过程中是以index表示的,但真实的情况下它需求memid(类型库成员编号)。

namespace TECHMARS.VM
{
    using System;
    using System.Runtime.InteropServices;
    using System.Runtime.InteropServices.ComTypes;
    using ELEMDESC = System.Runtime.InteropServices.ComTypes.ELEMDESC;
    using FUNCDESC = System.Runtime.InteropServices.ComTypes.FUNCDESC;
    using TYPEATTR = System.Runtime.InteropServices.ComTypes.TYPEATTR;

    unsafe class Program
    {
        [ComImport, Guid("00020400-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IDispatch
        {
            void Reserved();
            [PreserveSig]
            int GetTypeInfo(uint nInfo, int lcid, [MarshalAs(UnmanagedType.Interface)]out ITypeInfo info);
        }

        [MTAThread]
        static void Main(string[] args)
        {
            IDispatch dispatch = Activator.CreateInstance(Type.GetTypeFromProgID("MSXML2.XMLHTTP")) as IDispatch;
            ITypeInfo info;
            if (dispatch.GetTypeInfo(0, 0, out info) == 0)
            {
                IntPtr p = IntPtr.Zero;
                info.GetTypeAttr(out p);

                TYPEATTR pTA = (TYPEATTR)Marshal.PtrToStructure(p, typeof(TYPEATTR));
                info.ReleaseTypeAttr(p);

                for (int i = 0; i < pTA.cFuncs; i++)
                {
                    info.GetFuncDesc(i, out p);
                    FUNCDESC pFD = (FUNCDESC)Marshal.PtrToStructure(p, typeof(FUNCDESC));
                    info.ReleaseFuncDesc(p);

                    string bstrName;
                    string bstrDocString;
                    int dwHelpContext;
                    string bstrHelpFile;
                    info.GetDocumentation(pFD.memid, out bstrName, out bstrDocString, out dwHelpContext, out bstrHelpFile);

                    int vtReturnType = pFD.elemdescFunc.tdesc.vt;

                    string bstrContents = string.Format("Name={0}, Comment={1}, HelpId={2}, HelpFile={3}, ReturnType={4}, ParamCount={5},", bstrName, bstrDocString,
                        dwHelpContext, bstrHelpFile, vtReturnType, pFD.cParams);

                    for (int j = 0; j < pFD.cParams; j++)
                    {
                        ELEMDESC* pED = (ELEMDESC*)pFD.lprgelemdescParam;
                        bstrContents += string.Format(" Slot={0}({1}),", pED[j].tdesc.vt, j);
                    }
                    Console.WriteLine(bstrContents);
                }
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/liulilittle/article/details/80677696