65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 TypeLibInfoTool 生成 IDL 和 Manifest 文件

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2011 年 11 月 1 日

CPOL

7分钟阅读

viewsIcon

47951

downloadIcon

2307

一个用于检查 COM 类型库并生成 IDL 和 .manifest 文件的应用程序。该工具是一个使用 JavaScript 作为逻辑的 HTML 应用程序。

引言

本文介绍了一个工具,用于检查任何 COM 类型库的接口,并生成其 IDL 文件或 *.manifest 文件片段,该片段可用于部署免注册应用程序。

其功能类似于许多前身,例如 VB6 IDE 的对象浏览器、Microsoft OLE View 等。与这些相比,它增加了脚本语言的简洁性和开放性,以及一些额外的功能,有助于编写无注册 COM 所需的 *.manifest 文件(参见 [1])。

背景

类型库是 COM 技术的核心。每个 COM 组件本身都以其接口表示,通过类型库。这些以多种类型的文件形式实现。

  • 动态链接库 (*.dll)。这可能是 COM 组件最常见的形式。
  • ActiveX 组件 (*.ocx)。它们是 DLL 的特例,具有特定的机制来将其实例化的对象嵌入到 GUI 中。
  • 可执行文件 (*.exe)。独立可执行文件也可以公开 COM 接口。这通常是为了提供从另一个应用程序以编程方式驱动应用程序的能力。
  • 类型库 (*.tlb)。此类文件中不包含代码,这是 IDL 文件的二进制形式,可用于在构建新组件时导入接口或引用类型库中的对象。

此工具利用了“TypeLib Information Object Library”,该库提供了一个用于浏览类型库的 API。可以在本文中找到此库的示例用法([2])。TLI 组件本身作为类型库实现,一个有趣的练习是使用此处介绍的应用程序检查它(文件是 TlbInf32.dll,通常位于 %SystemRoot%\system32 中)。

此工具依赖的另一个主要技术是 Microsoft HTML 应用程序 (HTA)。这为决定深入研究源代码的用户提供了灵活性,因为它以 HTML 和 JavaScript 的形式立即在执行的同一个文件中可用。

用法

TLI 组件不是 Windows 安装的标准部分。它随其他软件(例如 Microsoft Visual Studio)一起提供。首先,请确保您的系统上注册了 TlbInf32.dll。如果没有,请获取一份副本并以常规方式注册它:转到安装它的文件夹(同样,通常是 C:\WINDOWS\system32),然后在命令行中键入以下内容。

regsvr32 TlbInf32.dll

完成此步骤后,即可开始。双击 TypeLibInfoTool.hta 文件,应用程序将启动。以下是其快照。

com_typelib_tool.png

从此时起,可以执行三项操作

  • 生成 IDL 文件
  • .manifest 文件的注册信息
  • 信息摘要

生成 IDL 文件

IDL 文件是构建 COM 组件时必不可少的部分。它定义了构成类型库接口的所有接口、协类、枚举等。它们通常用于 C/C++ 项目中。通常需要检查最初用于制作 COM 组件的 IDL 文件;虽然这很少可用,但可以重建。此外,导致 COM 组件的 VB6 项目不明确使用 IDL 文件,这通常是一个问题,因为一些基本信息被隐藏了。同样,重建 IDL 文件的能力至关重要。有关此主题的有趣网页可以在此处找到 [3]

TypeLibInfoTool 允许此操作;通过单击“生成 IDL”按钮,可以从二进制文件(DLL、OCX、EXE、TLB)重建 IDL 文件。

.manifest 文件的注册信息

应用程序传统上通过在注册表中查找 COM 组件的位置(和其他信息)来使用它们。这是可能的,因为每个组件都经过一个注册阶段,其信息被写入注册表。这通常在安装软件时完成。这始终是 OLE/COM 使用的模型。虽然对于许多目的来说完全没问题,但有时一键部署更受欢迎。最近,从 Windows XP 开始,可以采用另一种方法(参见 [4])。在可执行文件所在的文件夹中可以存在一个特殊文件,其中包含所有注册信息,该文件与可执行文件同名,并附加 .manifest 扩展名。操作系统检查此文件的存在,并在查找 Windows 注册表之前使用它。这消除了注册阶段的需要。

清单文件以 XML 格式编写,其格式可能难以手动编写。所提出的应用程序生成清单文件的片段,其中包含特定组件所需的注册信息。例如,考虑以下片段。

<file name='C:\WINDOWS\system32\msscript.ocx'>
    <typelib tlbid='{0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}' version='1.0' flags='' helpdir=''/>
    <comClass progid='MSScriptControl.Procedure' 
      clsid='{0E59F1DA-1FBE-11D0-8FF2-00A0D10038BC}' 
      threadingModel='Apartment'/>
    <comClass progid='MSScriptControl.Procedures' 
      clsid='{0E59F1DB-1FBE-11D0-8FF2-00A0D10038BC}' 
      threadingModel='Apartment'/>
    <comClass progid='MSScriptControl.Module' 
      clsid='{0E59F1DC-1FBE-11D0-8FF2-00A0D10038BC}' 
      threadingModel='Apartment'/>
    <comClass progid='MSScriptControl.Modules' 
      clsid='{0E59F1DD-1FBE-11D0-8FF2-00A0D10038BC}' 
      threadingModel='Apartment'/>
    <comClass progid='MSScriptControl.Error' 
      clsid='{0E59F1DE-1FBE-11D0-8FF2-00A0D10038BC}' 
      threadingModel='Apartment'/>
    <comClass progid='MSScriptControl.ScriptControl' 
      clsid='{0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC}' 
      threadingModel='Apartment'/>
</file>
<comInterfaceExternalProxyStub
    name='IScriptProcedure'
    iid='{70841C73-067D-11D0-95D8-00A02463AB28}'
    proxyStubClsid32='{00020424-0000-0000-C000-000000000046}'
    baseInterface='{00000000-0000-0000-C000-000000000046}'
    tlbid = '{0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}'/>
<comInterfaceExternalProxyStub
    name='IScriptProcedureCollection'
    iid='{70841C71-067D-11D0-95D8-00A02463AB28}'
    proxyStubClsid32='{00020424-0000-0000-C000-000000000046}'
    baseInterface='{00000000-0000-0000-C000-000000000046}'
    tlbid = '{0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}'/>
<comInterfaceExternalProxyStub
    name='IScriptModule'
    iid='{70841C70-067D-11D0-95D8-00A02463AB28}'
    proxyStubClsid32='{00020424-0000-0000-C000-000000000046}'
    baseInterface='{00000000-0000-0000-C000-000000000046}'
    tlbid = '{0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}'/>
<comInterfaceExternalProxyStub
    name='IScriptModuleCollection'
    iid='{70841C6F-067D-11D0-95D8-00A02463AB28}'
    proxyStubClsid32='{00020424-0000-0000-C000-000000000046}'
    baseInterface='{00000000-0000-0000-C000-000000000046}'
    tlbid = '{0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}'/>
<comInterfaceExternalProxyStub
    name='IScriptError'
    iid='{70841C78-067D-11D0-95D8-00A02463AB28}'
    proxyStubClsid32='{00020424-0000-0000-C000-000000000046}'
    baseInterface='{00000000-0000-0000-C000-000000000046}'
    tlbid = '{0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}'/>
<comInterfaceExternalProxyStub
    name='IScriptControl'
    iid='{0E59F1D3-1FBE-11D0-8FF2-00A0D10038BC}'
    proxyStubClsid32='{00020424-0000-0000-C000-000000000046}'
    baseInterface='{00000000-0000-0000-C000-000000000046}'
    tlbid = '{0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}'/>
<comInterfaceExternalProxyStub
    name='DScriptControlSource'
    iid='{8B167D60-8605-11D0-ABCB-00A0C90FFFC0}'
    proxyStubClsid32='{00020424-0000-0000-C000-000000000046}'
    baseInterface='{00000000-0000-0000-C000-000000000046}'
    tlbid = '{0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}'/>

这是 TypeLibInfoTool 对组件 msscript.ocx(用于在应用程序中执行脚本)的输出。这样的片段可以插入到具有以下结构的清单文件中(此示例中的文件可以命名为 all_needed_components.manifest)。

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
  <assemblyIdentity name='all_needed_components' type='win32' version='1.0'/>
  <description>All the needed COM components by our application</description>
  <file name='...'>
  </file>
  ...
</assembly>

当应用程序使用的所有组件都插入到此清单文件中时,它就可以用于我们的一键式应用程序。实际上,仍然需要一个与应用程序同名的另一个清单文件(例如,对于名为 MyRegistrationFreeApp.exe 的可执行文件,为 MyRegistrationFreeApp.exe.manifest)。正是此文件引用了包含所有注册信息的清单文件。这是一个示例

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
  <assemblyIdentity name='MyRegistrationFreeApp' 
         processorArchitecture='X86' type='win32' version='1.0' />
  <description>My Registration-Free Application</description>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity name='all_needed_components' 
              type='win32' version='1.0.0.0' />
    </dependentAssembly>
  </dependency>
</assembly>

关于免注册 COM 的最后一个警告:当组件作为可执行文件实现时,此机制不起作用。由于某种原因,Microsoft 工程师决定将可执行文件排除在外,因此它们仍然需要注册。还要记住,XP 之前的 Windows 操作系统需要以传统方式注册所有组件。

信息摘要

TypeLibInfoTool 的第三个操作是生成类型库接口信息的摘要。这只是简单地通过列举每个接口及其方法和属性、每个协类及其派生接口等来操作。该工具相当简单,但可用于在运行上述操作之一之前快速检查 COM 组件。

设计

该应用程序是一个 HTML 应用程序。这意味着它是一种特殊的网页,显示在应用程序框架中而不是网络浏览器中,并且在访问系统资源或在 COM 组件中执行代码时不受通常的限制。所有逻辑都作为 JavaScript 函数在网页中实现。

此代码的大部分使用 TypeLib Information Object Library (TLI) 来枚举组件中的信息并根据所需任务(即生成 IDL 或清单文件)进行处理。正如待办事项部分所指出的,这为扩展应用程序以进行其他操作(例如自动化文档)留下了空间。

待办

一些理想的功能已被排除在外,这些工作的进展将取决于本文所能引起的影响。

  • 并非类型库中包含的所有信息都已处理。例如,IDL 生成中仍然缺少 `importlib(...)` 指令。
  • 复制粘贴是获取工具信息的唯一方法。可以添加一个“保存”按钮。
  • 用于生成 IDL 文件的枚举所有接口、协类、枚举等的功能可以很容易地修改,以自动生成类型库的文档。最好的方法是生成 IDL 文件的 XML 版本,并依赖于外部 XML 样式表。
  • 此应用程序围绕从“单个”COM 组件中检索信息的概念而设计。当需要为应用程序生成清单文件时,这会带来限制,因为通常需要从多个文件中收集信息。因此,需要一些手动复制粘贴的工作。如果 TypeLibInfoTool 能在更大程度上帮助自动化此任务就好了。

参考文献

© . All rights reserved.