Compilation 扫描COM引用以帮助生成无注册COM清单

Compilation 扫描COM引用以帮助生成无注册COM清单,compilation,com,windows-installer,installshield,dependency-management,Compilation,Com,Windows Installer,Installshield,Dependency Management,我正在InstallShield 2015中以MSI安装程序的身份重新实施一个大型安装项目(它以前是InstallShield更旧版本的InstallScript安装程序)。我想做的许多改进之一是,通过使用清单文件和遵循无注册COM激活模式,允许以无注册的方式解析所有COM引用。我认为这不可能在所有情况下都实现,因为我们有一些MMC管理单元,据我所知,它们不能使用reg free COM,但我希望尽可能接近 挑战在于找出我需要创建的所有清单。我们提供数千个文件。我正在寻找一个实用程序,可以帮助扫

我正在InstallShield 2015中以MSI安装程序的身份重新实施一个大型安装项目(它以前是InstallShield更旧版本的InstallScript安装程序)。我想做的许多改进之一是,通过使用清单文件和遵循无注册COM激活模式,允许以无注册的方式解析所有COM引用。我认为这不可能在所有情况下都实现,因为我们有一些MMC管理单元,据我所知,它们不能使用reg free COM,但我希望尽可能接近

挑战在于找出我需要创建的所有清单。我们提供数千个文件。我正在寻找一个实用程序,可以帮助扫描文件,以确定:

  • 哪些文件代表COM服务器,它们包含哪些CLSID
  • 哪些文件代表COM客户端,它们引用哪些CLSID
  • 希望有了这些信息,我可以使用InstallShield的Reg Free COM向导生成必要的清单文件

    已经有什么东西可以帮上忙了吗?如果还没有实用程序,我将尝试通过以下方式编写自己的实用程序:

  • 查看COM服务器中的一些已知CLSID,并尝试识别它们周围的一些签名字节,这可能有助于我确定如何在COM服务器中识别CLSID
  • 编写代码在所有二进制文件中查找此签名,并提取所有CLSID
  • 在所有二进制文件中搜索已知的CLSID,并假设那些来自服务器外部的文件代表客户端
  • 如果事实证明我们使用的是ProgId,而不仅仅是CLSID,我可能不得不调整我的策略,但我希望这将涵盖我们COM引用的大部分


    如果已经有任何实用程序可能对此有所帮助,我想使用它,而不是自己编写。因此,我正在寻找任何关于自己写这篇文章的技巧,或者找到已经完成这篇文章的地方的技巧。

    在删除的答案的帮助下,我找到了一个类型库阅读类的C#源代码,我能够阅读类型库以获取CLSID值(如果尝试加载类型库失败,则跳过文件-只是尝试从每个可执行文件加载类型库)。然后,我对所有可执行文件进行了简单搜索,以查找那些CLSID值。我不确定结果是否完整,但它们至少看起来有点有效

    GetDirCLSIDRefs
    函数是顶级函数,它返回一个可执行文件名列表,并为每个文件返回一个关联文件列表,这些文件的类型库包含该文件引用的CLSID

    Private Function GetDirCLSIDRefs(目录作为字符串,CLSIDs作为KeyValuePair(Guid的字符串)()作为KeyValuePair(字符串的字符串)()
    Dim结果作为新列表(KeyValuePair(String,String())的)
    Dim entries=New System.IO.DirectoryInfo(Directory.GetFileSystemInfos())
    对于条目中的每个条目
    如果条目类型为System.IO.FileInfo和ALSO_
    (entry.Name.EndsWith(“.exe”)或_
    entry.Name.EndsWith(“.dll”)或lse_
    entry.Name.EndsWith(“.ocx”))然后
    Dim refs=ScanForCLSIDs(entry.FullName,CLSIDs)
    如果refs不是Nothing,并且refs.Length>0,则result.Add(新的KeyValuePair(字符串的,String())(entry.FullName,refs))
    否则,如果条目类型为System.IO.DirectoryInfo,则
    result.AddRange(GetDirCLSIDRefs(entry.FullName,CLSIDs))
    如果结束
    下一个
    返回result.ToArray()
    端函数
    私有函数GetDirCLSIDs(目录作为字符串)作为KeyValuePair(Guid的字符串)()
    Dim结果作为新列表(KeyValuePair的(Guid的,字符串的))
    Dim entries=New System.IO.DirectoryInfo(Directory.GetFileSystemInfos())
    对于条目中的每个条目
    如果条目类型为System.IO.FileInfo和ALSO_
    (entry.Name.EndsWith(“.exe”)或_
    entry.Name.EndsWith(“.dll”)或lse_
    entry.Name.EndsWith(“.ocx”))然后
    对于GetCLSIDs中的每个clsid(entry.FullName)
    添加(新的KeyValuePair(Guid、字符串)(clsid、entry.FullName))
    下一个
    否则,如果条目类型为System.IO.DirectoryInfo,则
    result.AddRange(GetDirCLSIDs(entry.FullName))
    如果结束
    下一个
    返回result.ToArray()
    端函数
    私有函数GetCLSIDs(文件名为字符串)作为Guid()
    Dim tlb=TypeLibTypes.Interop.TypeLib.Load(文件名)
    如果tlb.GetTypeLib()为Nothing,则返回{}
    Dim结果作为新列表(Guid)
    尝试
    对于tlb.GetTypeInfoCount()-1,typeIndex为整数=0
    使用attr=tlb.GetTypeInfo(typeIndex.GetTypeAttr()
    如果(attr.wtypeblags和TypeLibTypes.Interop.TYPEFLAGS.TYPEFLAG\u FHIDDEN)=0_
    AndAlso attr.typekind=TypeLibTypes.Interop.typekind.TKIND_COCLASS然后
    结果.添加(属性Guid)
    如果结束
    终端使用
    下一个
    当ex.ErrorCode=&H80029C4A时,将ex捕获为System.Runtime.InteropServices.COMException
    返回{}
    结束尝试
    返回result.ToArray()
    端函数
    私有函数ScanForCLSIDs(文件名为String,CLSIDFiles为KeyValuePair(Guid的字符串)()为String())
    将内容设置为字节()
    使用文件作为新System.IO.FileStream(文件名,IO.FileMode.Open,IO.FileAccess.Read,IO.FileShare.ReadWrite)
    content=DirectCast(Array.CreateInstance(GetType(Byte)、CInt(file.Length))、Byte())
    file.Read(content,0,CInt(file.Length))
    终端使用
    将结果变暗为新列表(字符串)
    对于CLSIDFiles中的每个CLSIDFiles
    如果FindBytes(content,CLSIDFile.Key.ToByteArray())>=0,则
    如果不是result.Contains(CLSIDFile.Value),则是result.Add(CLSIDFile.Value)
    如果结束
    下一个
    返回result.ToArray()
    端函数
    私有函数FindBytes(数据为Byte(),模式为Byte(),可选开始为Integer=0)为Int32
    如果pattern.Length=0,则返回-1
    如果data.Length=0,则返回0
    暗淡的