首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >扫描COM引用以帮助生成无Reg的COM清单

扫描COM引用以帮助生成无Reg的COM清单
EN

Stack Overflow用户
提问于 2015-10-16 14:14:33
回答 1查看 61关注 0票数 0

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

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

  1. 哪些文件表示COM服务器,以及它们包含哪些CLSID
  2. 哪些文件代表COM客户端,以及它们引用哪些CLSID?

希望有了这些信息,我就可以使用InstallShield的Reg向导生成必要的清单文件。

已经有什么能帮上忙了吗?如果已经没有实用程序,我将尝试通过以下方法编写自己的工具:

  1. 查看COM服务器中的一些已知CLSID,并试图识别它们周围的一些签名字节,这些字节可能帮助我确定如何在一般COM服务器中识别CLSID。
  2. 编写代码,在所有二进制文件中查找此签名,并获取所有CLSID。
  3. 搜索所有二进制文件以获得已知的CLSID,并假定来自服务器外部的文件代表客户端。

如果我们使用的是ProgId,而不仅仅是CLSID,我可能不得不调整我的策略,但我希望这将涵盖我们的大部分COM引用。

如果已经有任何实用程序可以帮助解决这个问题,我想使用它而不是编写自己的工具。因此,我正在寻找任何关于自己写这篇文章的技巧,或者关于找到这件事已经完成的地方的建议。

EN

Stack Overflow用户

回答已采纳

发布于 2015-10-16 21:18:38

在已删除的对How to read TLB (type libraries) of unmanaged code from C#?的答复(这导致我在http://clrinterop.codeplex.com/releases/view/17579上找到了类型库读取类的C#源代码)的帮助下,我能够读取类型库来获取CLSID值(如果加载类型库的尝试失败,则跳过文件--只是尝试从每个可执行文件加载一个库)。然后,我对所有可执行文件进行了简单搜索,以查找那些CLSID值。我不知道结果有多完整,但它们看起来至少是有效的。

GetDirCLSIDRefs函数是顶级函数,它返回可执行文件名的列表,对于每个文件,返回类型库包含文件引用的CLSID的关联文件列表。

代码语言:javascript
运行
复制
Private Function GetDirCLSIDRefs(Directory As String, CLSIDs As KeyValuePair(Of Guid, String)()) As KeyValuePair(Of String, String())()
   Dim result As New List(Of KeyValuePair(Of String, String()))
   Dim entries = New System.IO.DirectoryInfo(Directory).GetFileSystemInfos()
   For Each entry In entries
      If TypeOf entry Is System.IO.FileInfo AndAlso _
         (entry.Name.EndsWith(".exe") OrElse _
          entry.Name.EndsWith(".dll") OrElse _
          entry.Name.EndsWith(".ocx")) Then
         Dim refs = ScanForCLSIDs(entry.FullName, CLSIDs)
         If refs IsNot Nothing AndAlso refs.Length > 0 Then result.Add(New KeyValuePair(Of String, String())(entry.FullName, refs))
      ElseIf TypeOf entry Is System.IO.DirectoryInfo Then
         result.AddRange(GetDirCLSIDRefs(entry.FullName, CLSIDs))
      End If
   Next
   Return result.ToArray()
End Function

Private Function GetDirCLSIDs(Directory As String) As KeyValuePair(Of Guid, String)()
   Dim result As New List(Of KeyValuePair(Of Guid, String))
   Dim entries = New System.IO.DirectoryInfo(Directory).GetFileSystemInfos()
   For Each entry In entries
      If TypeOf entry Is System.IO.FileInfo AndAlso _
         (entry.Name.EndsWith(".exe") OrElse _
          entry.Name.EndsWith(".dll") OrElse _
          entry.Name.EndsWith(".ocx")) Then
         For Each clsid In GetCLSIDs(entry.FullName)
            result.Add(New KeyValuePair(Of Guid, String)(clsid, entry.FullName))
         Next
      ElseIf TypeOf entry Is System.IO.DirectoryInfo Then
         result.AddRange(GetDirCLSIDs(entry.FullName))
      End If
   Next
   Return result.ToArray()
End Function

Private Function GetCLSIDs(FileName As String) As Guid()
   Dim tlb = TypeLibTypes.Interop.TypeLib.Load(FileName)
   If tlb.GetTypeLib() Is Nothing Then Return {}
   Dim result As New List(Of Guid)
   Try
      For typeIndex As Integer = 0 To tlb.GetTypeInfoCount() - 1
         Using attr = tlb.GetTypeInfo(typeIndex).GetTypeAttr()
            If (attr.wTypeFlags And TypeLibTypes.Interop.TYPEFLAGS.TYPEFLAG_FHIDDEN) = 0 _
               AndAlso attr.typekind = TypeLibTypes.Interop.TYPEKIND.TKIND_COCLASS Then
               result.Add(attr.Guid)
            End If
         End Using
      Next
   Catch ex As System.Runtime.InteropServices.COMException When ex.ErrorCode = &H80029C4A
      Return {}
   End Try
   Return result.ToArray()
End Function

Private Function ScanForCLSIDs(FileName As String, CLSIDFiles As KeyValuePair(Of Guid, String)()) As String()
   Dim content As Byte()
   Using file As New System.IO.FileStream(FileName, 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))
   End Using
   Dim result As New List(Of String)
   For Each CLSIDFile In CLSIDFiles
      If FindBytes(content, CLSIDFile.Key.ToByteArray()) >= 0 Then
         If Not result.Contains(CLSIDFile.Value) Then result.Add(CLSIDFile.Value)
      End If
   Next
   Return result.ToArray()
End Function

Private Function FindBytes(data As Byte(), pattern As Byte(), Optional start As Integer = 0) As Int32
   If pattern.Length = 0 Then Return -1
   If data.Length = 0 Then Return 0
   Dim search = ProcessSearchPattern(pattern)
   Dim i As Integer = start + pattern.Length - 1
   Do While i < data.Length
      Dim j As Integer = pattern.Length - 1
      Do While j >= 0 AndAlso data(i) = pattern(j)
         i -= 1
         j -= 1
      Loop
      If j < 0 Then Return i + 1
      i += Math.Max(search.Delta1(data(i)), search.Delta2(j))
   Loop
   Return -1
End Function

Private Class SearchPattern
   Public Delta1 As Integer()
   Public Delta2 As Integer()
End Class

Private Class PatternBytes
   Private bytes As Byte()
   Public Sub New(value As Byte())
      bytes = value
   End Sub
   Public Overrides Function GetHashCode() As Integer
      Dim i As Integer = 0
      GetHashCode = 0
      Do While i <= bytes.Length - 4
         GetHashCode = GetHashCode Xor BitConverter.ToInt32(bytes, i)
         i += 4
      Loop
      If i <= bytes.Length - 2 Then
         GetHashCode = GetHashCode Xor BitConverter.ToInt16(bytes, i)
         i += 2
      End If
      If i < bytes.Length Then
         GetHashCode = GetHashCode Xor bytes(i)
      End If
   End Function

   Public Overrides Function Equals(obj As Object) As Boolean
      Dim compare As Byte()
      If TypeOf obj Is PatternBytes Then
         compare = DirectCast(obj, PatternBytes).bytes
      ElseIf TypeOf obj Is Byte() Then
         compare = DirectCast(obj, Byte())
      Else
         Return False
      End If
      If compare.Length <> bytes.Length Then Return False
      For i As Integer = 0 To bytes.Length - 1
         If bytes(i) <> compare(i) Then Return False
      Next
      Return True
   End Function
End Class

Private Function ProcessSearchPattern(pattern As Byte()) As SearchPattern
   Static cache As New Dictionary(Of PatternBytes, SearchPattern)
   ProcessSearchPattern = Nothing
   Dim pb As New PatternBytes(pattern)
   If cache.TryGetValue(pb, ProcessSearchPattern) Then Exit Function
   ProcessSearchPattern = New SearchPattern()
   Dim patLen = pattern.Length
   ProcessSearchPattern.Delta1 = DirectCast(Array.CreateInstance(GetType(Integer), Byte.MaxValue + 1), Integer())
   ProcessSearchPattern.Delta2 = DirectCast(Array.CreateInstance(GetType(Integer), patLen), Integer())
   Dim c As Integer ' Cannot run a For loop to Byte.MaxValue in a Byte!
   Dim i As Integer
   For c = 0 To Byte.MaxValue
      ProcessSearchPattern.Delta1(c) = patLen
   Next
   For i = 0 To patLen - 2
      ProcessSearchPattern.Delta1(pattern(i)) = patLen - 1 - i
   Next

   Dim m As Integer
   Dim lastPrefixIndex = patLen - 1
   Dim isPrefix As Boolean = False
   For i = patLen - 1 To 0 Step -1
      isPrefix = True
      If patLen - i - 2 > 0 Then
         For m = 0 To patLen - i - 2
            If pattern(m) <> pattern(m + i + 1) Then
               isPrefix = False
               Exit For
            End If
         Next
      End If
      If isPrefix Then lastPrefixIndex = i + 1
      ProcessSearchPattern.Delta2(i) = lastPrefixIndex + (patLen - 1 - i)
   Next

   For i = 0 To patLen - 2
      For m = 0 To i - 1
         If pattern(i - m) = pattern(patLen - 1 - m) Then
            Exit For
         End If
         If pattern(i - m) <> pattern(patLen - 1 - m) Then
            ProcessSearchPattern.Delta2(patLen - 1 - m) = patLen - 1 - i + m
         End If
      Next
   Next

   cache.Add(pb, ProcessSearchPattern)
End Function
票数 0
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33172656

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档