如何使用Python27提取.msi格式文件的图标
Python2.7环境下MSI文件信息与图标提取实现方案
根因说明
此前使用msilib认为其仅支持MSI创建的核心原因,是该库的设计定位以简化MSI包生成流程为主,读取相关接口仅做了Windows Installer数据库的底层绑定,没有封装便捷的查询、二进制读取工具方法,才会给用户造成不支持读取的感知。实际上Python2.7自带的msilib完整绑定了Windows Installer的数据库操作接口,只要按照MSI内部的系统表结构编写对应查询语句,即可完成全量信息读取。
环境准备
- 无需引入大型第三方依赖,Python2.7自带的
msilib库即可覆盖90%以上的常规MSI读取场景 - 遇到复杂结构MSI打开报错的兼容问题,安装适配Python2.7的olefile版本:
pip install olefile==0.46,该版本是最后一个完整支持Python2.7的olefile发行版,可辅助修复部分特殊打包MSI的OLE结构读取异常
基础信息提取实现
MSI的产品名称、版本、厂商等核心元信息,全部存储在Property系统表中,通过标准SQL查询即可获取,核心代码逻辑:
import msilib # 以只读模式打开MSI,不开启写权限避免修改原文件 db = msilib.OpenDatabase(r"C:\path\to\your.msi", msilib.MSIDBOPEN_READONLY) # 打开属性表查询视图 cursor = db.OpenView("SELECT Property, Value FROM Property") cursor.Execute(None) # 遍历查询结果存储为字典 msi_metadata = {} record = cursor.Fetch() while record: prop_key = record.GetString(1) prop_val = record.GetString(2) msi_metadata[prop_key] = prop_val record = cursor.Fetch() # 可直接读取常见字段:ProductName、ProductVersion、Manufacturer、ProductCode等
内嵌图标提取实现
MSI内的所有图标资源全部存储在Icon系统表中,表内的Data字段直接保存了完整的ICO格式二进制内容,提取时需要特别注意二进制流的读取方式,避免编码转换损坏内容:
# 打开Icon表查询视图 icon_cursor = db.OpenView("SELECT Name, Data FROM Icon") icon_cursor.Execute(None) icon_record = icon_cursor.Fetch() while icon_record: # 读取图标名称作为本地保存文件名 icon_file_name = icon_record.GetString(1) # 按字段实际大小读取全量二进制流,禁止用字符串方法读取 stream_len = icon_record.FieldDataSize(2) icon_binary = icon_record.ReadStream(2, stream_len) # 写入本地ico文件 with open(f"./output/{icon_file_name}.ico", "wb") as f: f.write(icon_binary) icon_record = icon_cursor.Fetch()
关键注意事项
- 读取二进制流时必须使用
ReadStream方法,禁止用GetString读取Data字段,会触发UTF-16编码转换直接损坏二进制内容 - 经过加密封装、自定义打包逻辑处理的特殊MSI包,无法通过标准数据库接口读取,需要先完成解密解包才能操作
- 不要使用zipfile等ZIP格式读取库解析MSI,MSI本质是OLE2复合文档结构,和ZIP格式无关联,常规解压库完全无法识别其内部结构
内容的提问来源于stack exchange,提问作者Crucian
相关产品推荐
相关产品推荐

