Search code examples
typelibregistration-free-com

Is there a way to view COM entries by traversing a TLB file in .NET?


I'm converting an application to use registration free COM. There are a few 3rd party COM dll's that would normally have regsvr32 called on them. I tested that I can create objects from these 3rd party dlls by making a side-by-side manifest.

I used the OLE/COM viewer built into Windows to get this information. However I would like to make a program that could do this for me manually, as these 3rd party libraries have lots of classes I need to put in the manifest.

Does anyone know of a way to programatically traverse a type library?


Solution

  • I took Hans' advice and used LoadTypeLib.

    For anyone looking for example code, this should be a great starting point. I wrote it this morning and was able to get xml that I needed.

    Forgive me for not releasing the objects! I don't have time to fully flesh out the rest of this answer right now. Edits are welcome.

        [DllImport("oleaut32.dll", PreserveSig = false)]
        public static extern ITypeLib LoadTypeLib([In, MarshalAs(UnmanagedType.LPWStr)] string typelib);
    
        public static void ParseTypeLib(string filePath)
        {
    
            string fileNameOnly = Path.GetFileNameWithoutExtension(filePath);
            ITypeLib typeLib = LoadTypeLib(filePath);
    
            int count = typeLib.GetTypeInfoCount();
            IntPtr ipLibAtt = IntPtr.Zero;
            typeLib.GetLibAttr(out ipLibAtt);
    
            var typeLibAttr = (System.Runtime.InteropServices.ComTypes.TYPELIBATTR)
                Marshal.PtrToStructure(ipLibAtt, typeof(System.Runtime.InteropServices.ComTypes.TYPELIBATTR));
            Guid tlbId = typeLibAttr.guid;
    
            for(int i=0; i< count; i++)
            {
                ITypeInfo typeInfo = null;
                typeLib.GetTypeInfo(i, out typeInfo);
    
                //figure out what guids, typekind, and names of the thing we're dealing with
                IntPtr ipTypeAttr = IntPtr.Zero;
                typeInfo.GetTypeAttr(out ipTypeAttr);
    
                //unmarshal the pointer into a structure into something we can read
                var typeattr = (System.Runtime.InteropServices.ComTypes.TYPEATTR)
                    Marshal.PtrToStructure(ipTypeAttr, typeof(System.Runtime.InteropServices.ComTypes.TYPEATTR));
    
                System.Runtime.InteropServices.ComTypes.TYPEKIND typeKind = typeattr.typekind;
                Guid typeId = typeattr.guid;
    
                //get the name of the type
                string strName, strDocString, strHelpFile;
                int dwHelpContext;
                typeLib.GetDocumentation(i, out strName, out strDocString, out dwHelpContext, out strHelpFile);
    
    
                if (typeKind == System.Runtime.InteropServices.ComTypes.TYPEKIND.TKIND_COCLASS)
                {
                    string xmlComClassFormat = "<comClass clsid=\"{0}\" tlbid=\"{1}\" description=\"{2}\" progid=\"{3}.{4}\"></comClass>";
                    string comClassXml = String.Format(xmlComClassFormat, 
                        typeId.ToString("B").ToUpper(),
                        tlbId.ToString("B").ToUpper(),
                        strDocString,
                        fileNameOnly, strName
                        );
                    //Debug.WriteLine(comClassXml);
                }
                else if(typeKind == System.Runtime.InteropServices.ComTypes.TYPEKIND.TKIND_INTERFACE)
                {
                    string xmlProxyStubFormat = "<comInterfaceExternalProxyStub name=\"{0}\" iid=\"{1}\" tlbid=\"{2}\" proxyStubClsid32=\"{3}\"></comInterfaceExternalProxyStub>";
                    string proxyStubXml = String.Format(xmlProxyStubFormat,
                        strName,
                        typeId.ToString("B").ToUpper(),
                        tlbId.ToString("B").ToUpper(),
                        "{00020424-0000-0000-C000-000000000046}"
                    );
                    //Debug.WriteLine(proxyStubXml);
                }
    
            }
    
            return;
        }
    }