"msilib" --- 读写 Microsoft Installer 文件
******************************************

**源代码:** Lib/msilib/__init__.py

从 3.11 版起不建议使用，将在 3.13 版中移除: "msilib" 模块已被弃用（请
参阅 **PEP 594** 了解详情）。

======================================================================

"msilib" 支持创建 Microsoft 安装程序 (".msi") 文件。 由于这种文件往往
包含一个嵌入的 "cabinet" 文件 (".cab")，它也暴露了一个用于创建 CAB 文
件的 API。  目前没有实现对读取 ".cab" 文件的支持；对于读取 ".msi" 数据
库的支持则是可能的。

这个包的目标是提供对 ".msi" 文件中的全部表的完整访问，因此，它是一个相
当低层级的 API。 这个包的一个主要应用是创建 Python 安装程序包本身 (尽
管它目前是使用不同版本的 "msilib")。

这个包的内容可以大致分为四个部分：低层级 CAB 例程、低层级 MSI 例程、高
层级 MSI 例程以及标准表结构。

msilib.FCICreate(cabname, files)

   新建一个名为 *cabname* 的 CAB 文件。 *files* 必须是一个元组的列表，
   其中每个元组包含磁盘文件的名称，以及 CAB 文件内文件的名称。

   这些文件将按照它们在列表中出现的顺序被添加到 CAB 文件中。 所有文件
   都会被添加到单个 CAB 文件，使用 MSZIP 压缩算法。

   目前没有暴露 MSI 创建的各个步骤对 Python 的回调。

msilib.UuidCreate()

   返回一个新的唯一标识符的字符串表示形式。 这封装了 Windows API 函数
   "UuidCreate()" 和 "UuidToString()"。

msilib.OpenDatabase(path, persist)

   通过调用 MsiOpenDatabase 来返回一个新的数据库对象。 *path* 为 MSI
   文件的名称；*persist* 可以是常量 "MSIDBOPEN_CREATEDIRECT",
   "MSIDBOPEN_CREATE", "MSIDBOPEN_DIRECT", "MSIDBOPEN_READONLY" 或
   "MSIDBOPEN_TRANSACT" 中的一个，并可能包括旗标 "MSIDBOPEN_PATCHFILE"
   。 请参阅 Microsoft 文档了解这些旗标的含义；根据这些旗标，将打开一
   个现有数据库，或者创建一个新数据库。

msilib.CreateRecord(count)

   通过调用 "MSICreateRecord()" 来返回一个新的记录对象。 *count* 为记
   录的字段数量。

msilib.init_database(name, schema, ProductName, ProductCode, ProductVersion, Manufacturer)

   创建并返回一个新的数据库 *name*，使用 *schema* 来初始化它，并设置属
   性 *ProductName*, *ProductCode*, *ProductVersion* 和 *Manufacturer*
   。

   *schema* 必须是一个包含 "tables" 和 "_Validation_records" 属性的模
   块对象；在通常情况下，"msilib.schema" 应当被使用。

   此此函数返回时该数据库将只包含表结构和验证记录。

msilib.add_data(database, table, records)

   将所有 *records* 添加到 *database* 中名为 *table* 的表。

   *table* 参数必须为 MSI 方案中预定义的表之一，即 "'Feature'",
   "'File'", "'Component'", "'Dialog'", "'Control'" 等等。

   *records* 应当为一个元组的列表，其中的每个元组都包含与表结构对应的
   记录的所有字段。 对于可选字段，可以传入 "None"。

   字段值可以为整数、字符串或 Binary 类的实例。

class msilib.Binary(filename)

   代表 Binary 表中的条目；使用 "add_data()" 插入这样的对象会将名为
   *filename* 文件读入表中。

msilib.add_tables(database, module)

   将来自 *module* 的所有表内容添加到 *database*。 *module* 必须包括一
   个列出其内容需要被添加的所有表的属性 *tables*，并且每个具有实际内容
   的表对应一个属性。

   这通常被用来安装序列表。

msilib.add_stream(database, name, path)

   将文件 *path* 添加到 *database* 的 "_Stream" 表，使用流名称 *name*
   。

msilib.gen_uuid()

   返回一个新的 UUID，符合 MSI 通常的格式要求（即外加花括号，且所有十
   六进制数码均为大写形式）。

参见: FCICreate UuidCreate UuidToString


数据对象
========

Database.OpenView(sql)

   通过调用 "MSIDatabaseOpenView()" 返回一个视图对象。 *sql* 是要执行
   的 SQL 语句。statement to execute.

Database.Commit()

   通过调用 "MSIDatabaseCommit()" 提交当前事务中挂起的修改。

Database.GetSummaryInformation(count)

   通过调用 "MsiGetSummaryInformation()" 返回一个新的概要信息对象。
   *count* 为已更新值的最大数量。

Database.Close()

   通过 "MsiCloseHandle()" 关闭数据库对象。

   在 3.7 版本加入.

参见:

  MSIDatabaseOpenView MSIDatabaseCommit MSIGetSummaryInformation
  MsiCloseHandle


视图对象
========

View.Execute(params)

   通过 "MSIViewExecute()" 执行视图的 SQL 查询。 如果 *params* 不为
   "None"，它应是一条描述查询中形参名称的实际值的记录。

View.GetColumnInfo(kind)

   通过调用 "MsiViewGetColumnInfo()" 返回一条描述视图的列的记录。
   *kind* 可以是 "MSICOLINFO_NAMES" 或 "MSICOLINFO_TYPES"。

View.Fetch()

   通过调用 "MsiViewFetch()" 返回查询的结果记录。

View.Modify(kind, data)

   通过调用 "MsiViewModify()" 改变视图。 *kind* 可以是
   "MSIMODIFY_SEEK"，"MSIMODIFY_REFRESH"，"MSIMODIFY_INSERT"，
   "MSIMODIFY_UPDATE"，"MSIMODIFY_ASSIGN"，"MSIMODIFY_REPLACE"，
   "MSIMODIFY_MERGE"，"MSIMODIFY_DELETE"，"MSIMODIFY_INSERT_TEMPORARY"
   ，"MSIMODIFY_VALIDATE"，"MSIMODIFY_VALIDATE_NEW"，
   "MSIMODIFY_VALIDATE_FIELD"，"MSIMODIFY_VALIDATE_DELETE" 中的一种。

   *data* 必须是一个描述新数据的记录。

View.Close()

   通过 "MsiViewClose()" 关闭窗口。

参见:

  MsiViewExecute MSIViewGetColumnInfo MsiViewFetch MsiViewModify
  MsiViewClose


对象总览
========

SummaryInformation.GetProperty(field)

   通过 "MsiSummaryInfoGetProperty()" 返回概要的特征属性。 *field* 是
   属性的名称，可以是常量 "PID_CODEPAGE", "PID_TITLE", "PID_SUBJECT",
   "PID_AUTHOR", "PID_KEYWORDS", "PID_COMMENTS", "PID_TEMPLATE",
   "PID_LASTAUTHOR", "PID_REVNUMBER", "PID_LASTPRINTED",
   "PID_CREATE_DTM", "PID_LASTSAVE_DTM", "PID_PAGECOUNT",
   "PID_WORDCOUNT", "PID_CHARCOUNT", "PID_APPNAME" 或 "PID_SECURITY"
   中的一个。

SummaryInformation.GetPropertyCount()

   通过 "MsiSummaryInfoGetPropertyCount()" 返回概要特征属性的数量。

SummaryInformation.SetProperty(field, value)

   通过 "MsiSummaryInfoSetProperty()" 设置特征属性。 *field* 可以有与
   "GetProperty()" 相同的值。 *value* 是属性的新值。 可用的值类型有整
   数和字符串。

SummaryInformation.Persist()

   使用 "MsiSummaryInfoPersist()" 将已修改的特征属性写入到概要信息流。

参见:

  MsiSummaryInfoGetProperty MsiSummaryInfoGetPropertyCount
  MsiSummaryInfoSetProperty MsiSummaryInfoPersist


记录对象
========

Record.GetFieldCount()

   通过 "MsiRecordGetFieldCount()" 返回记录字段的数量。

Record.GetInteger(field)

   在可能的情况下将 *field* 的值以整数形式返回。 *field* 必须为整数。

Record.GetString(field)

   在可能的情况下将 *field* 的值以字符串形式返回。 *field* 必须为整数
   。

Record.SetString(field, value)

   通过 "MsiRecordSetString()" 将 *field* 设为 *value*。 *field* 必须
   是一个整数；*value* 是一个字符串。

Record.SetStream(field, value)

   通过 "MsiRecordSetStream()" 将 *field* 设为名为 *value* 的文件的内
   容。 *field* 必须是一个整数；*value* 是一个字符串。

Record.SetInteger(field, value)

   通过 "MsiRecordSetInteger()" 将 *field* 设为 *value*。 *field* 和
   *value* 必须为整数。

Record.ClearData()

   通过 "MsiRecordClearData()" 将记录的所有字段设为 0。

参见:

  MsiRecordGetFieldCount MsiRecordSetString MsiRecordSetStream
  MsiRecordSetInteger MsiRecordClearData


错误
====

所有 MSI 函数的包装器都会引发 "MSIError"；异常内部的字符串将包含更多细
节。


CAB 对象
========

class msilib.CAB(name)

   "CAB" 类代表一个 CAB 文件。 在 MSI 构建过程中，文件将被同时添加到
   "Files" 表，以及 CAB 中。 然后，当所有文件添加完成时，即可写入 CAB
   文件，再添加到 MSI 文件中。

   *name* 是 MSI 文件中 CAB 文件的名称。

   append(full, file, logical)

      将路径名为 *full* 的文件添加到 CAB 文件中，命名为 *logical*。 如
      果已存在名为 *logical* 的文件，则会创建一个新的文件名。

      返回文件在 CAB 文件中的索引，以及文件在 CAB 文件中的新名称。

   commit(database)

      生成一个 CAB 文件，以流方式添加到 MSI 文件，将其放入 "Media" 表
      ，并从磁盘移除所生成的文件。


目录对象
========

class msilib.Directory(database, cab, basedir, physical, logical, default[, componentflags])

   在目录表中创建一个新目录。 在每个时点上对于该目录都有一个当前组件，
   它或是通过 "start_component()" 显式创建，或是在文件首次被加入时隐式
   创建。 文件会被加入当前组件，并被加入到 cab 文件中。 要创建一个目录
   ，必须指定一个基准目录对象 (可以为 "None")，指向物理目录的路径，以
   及一个逻辑目录名称。 *default* 指明目录表中的 DefaultDir 槽位。
   *componentflags* 指明新组件所获得的默认旗标。

   start_component(component=None, feature=None, flags=None, keyfile=None, uuid=None)

      向组件表添加一个条目，并将该组件设为此目录的当前组件。 如果未给
      出组件名称，则将使用目录名称。 如果未给出 *feature*，则将使用当
      前特征。 如果未给出 *flags*，则将使用目录的默认旗标。 如果未给出
      *keyfile*，则组件表中的 KeyPath 将保持为空值。

   add_file(file, src=None, version=None, language=None)

      向目录的当前组件添加一个文件，如果没有当前组件则会新建一个。 在
      默认情况下，源中的文件名和文件表将保持一致。 如果指定了 *src* 文
      件，它将被解读为相对于当前目录。 作为可选项，可以为文件表中的条
      目指定 *version* 和 *language*。

   glob(pattern, exclude=None)

      向当前组件添加一个通过 glob 模式指定的文件列表。 单个文件可以在
      *exclude* 列表中排除。

   remove_pyc()

      在卸载时移除 ".pyc" 文件。

参见: Directory Table File Table Component Table FeatureComponents Table


相关特性
========

class msilib.Feature(db, id, title, desc, display, level=1, parent=None, directory=None, attributes=0)

   使用值 *id*, *parent.id*, *title*, *desc*, *display*, *level*,
   *directory* 和 *attributes* 向 "Feature" 表添加一条新记录。 结果特
   征对象可被传给 "Directory" 的 "start_component()" 方法。

   set_current()

      将此特征设为 "msilib" 的当前特征。 新组件会自动被添加到默认特征
      ，除非显式指定了一个特征。

参见: 特征表


GUI 类
======

"msilib" 提供了一些在 MSI 数据库中包装 GUI 表的类。 但是，并未提供标准
用户接口。

class msilib.Control(dlg, name)

   对话框控件的基类。 *dlg* 是控件所属的对话框对象，*name* 是控件的名
   称。

   event(event, argument, condition=1, ordering=None)

      在 "ControlEvent" 表中为该控件创建一个条目。

   mapping(event, attribute)

      在 "EventMapping" 表中为该控件创建一个条目。

   condition(action, condition)

      在 "ControlCondition" 表中为该控件创建一个条目。

class msilib.RadioButtonGroup(dlg, name, property)

   创建一个名为 *name* 的单选钮控件。 *property* 是当单选钮被选中时设
   置的安装器属性。

   add(name, x, y, width, height, text, value=None)

      向分组添加一个名为 *name* 的单选钮，设置坐标为 *x*, *y*,
      *width*, *height*，标签为 *text*。 如果 *value* 为 "None"，则设
      置默认值 *name*。

class msilib.Dialog(db, name, x, y, w, h, attr, title, first, default, cancel)

   返回一个新的 "Dialog" 对象。 将在 "Dialog" 表中创建一个条目，设置指
   定的坐标，对话框属性，标题，首个、默认和取消控件的名称。

   control(name, type, x, y, width, height, attributes, property, text, control_next, help)

      返回一个新的 "Control" 对象。 将在 "Control" 表中创建带有指定形
      参的条目。

      这是一个通用方法；对于特定的类型，还提供了专用的方法。

   text(name, x, y, width, height, attributes, text)

      添加并返回一个 "Text" 控件。

   bitmap(name, x, y, width, height, text)

      添加并返回一个 "Bitmap" 控件。

   line(name, x, y, width, height)

      添加并返回一个 "Line" 控件。

   pushbutton(name, x, y, width, height, attributes, text, next_control)

      添加并返回一个 "PushButton" 控件。

   radiogroup(name, x, y, width, height, attributes, property, text, next_control)

      添加并返回一个 "RadioButtonGroup" 控件。

   checkbox(name, x, y, width, height, attributes, property, text, next_control)

      添加并返回一个 "CheckBox" 控件。

参见:

  Dialog Table Control Table Control Types ControlCondition Table
  ControlEvent Table EventMapping Table RadioButton Table


预计算的表
==========

"msilib" 提供了一些仅包含结构模式和表定义的子包。 这些定义基于 MSI 2.0
版。

msilib.schema

   这是基于 MSI 2.0 的标准 MSI 结构模式，其中 *tables* 变量提供了一个
   由表定义组成的列表，而 *_Validation_records* 提供了用于 MSI 验证的
   数据。

msilib.sequence

   此模块包含针对标准序列表的表内容: *AdminExecuteSequence*,
   *AdminUISequence*, *AdvtExecuteSequence*, *InstallExecuteSequence*
   和 *InstallUISequence*。

msilib.text

   此模块包含 UIText 和 ActionText 表的定义，用于标准安装器动作。
