我可以使用msilib或其他Python库从.msi文件中提取一个文件吗?

时间:2013-03-20 18:53:51

标签: python wix windows-installer

我真正想要做的是确定MSI中的特定文件是否存在并包含特定字符串。

我目前的想法是:

 db = msilib.OpenDatabase('c:\Temp\myfile.msi',1)
 query = "select * from File"
 view = db.OpenView(query)
 view.Execute(None)
 cur_record = view.Fetch()     # do this until I get the record I want
 print cur_record.GetString(3) # do stuff with this value

然后如果它在那里,使用

提取所有文件
msiexec /a c:\Temp\myfile.msi /qn TARGETDIR=c:\foo

并使用任何解析器来查看我的字符串是否存在。但我希望存在一种不那么笨重的方式。

3 个答案:

答案 0 :(得分:3)

请注意,正如msilib的文档所说,“目前尚未实现”支持读取.cab文件“。和。更一般地说,该库设计用于构建.msi文件,而不是读取它们。 stdlib中没有任何其他东西可以做你想做的事。

所以,有几种可能性:

  1. 查找并安装另一个库,例如pycabinet。我对这个特定的图书馆一无所知;这只是我得到的第一次搜索;你可能想自己搜索。但它声称为CAB文件提供了类似zipfile的API,这听起来就像你缺少的部分。
  2. 使用win32com(如果您有pywin32)或ctypes(如果您是受虐狂)与基础COM接口和/或经典Cabinet API进行通信(我认为现在已弃用,但仍然有效。)
  3. 使用IronPython而不是CPython,因此您可以使用更简单的.NET接口。
  4. 由于我这里没有Windows框,我无法对此进行测试,但这里是使用IronPython而不是C#编写的Christopher Painter .NET解决方案的草图:

    import clr
    clr.AddReference('Microsoft.Deployment.WindowsInstaller')
    clr.AddReference('Microsoft.Deployment.WindowsInstaller.Package')
    from Microsoft.Deployment.WindowsInstaller import *
    from Microsoft.Deployment.WindowsInstaller.Package import *
    
    def FindAndExtractFiles(packagePath, longFileName):
        with InstallPackage(packagePath, DatabaseOpenMode.ReadOnly) as installPackage:
            if installPackage.FindFiles(longFileName).Count() > 0:
                installPackage.ExtractFiles()
    

答案 1 :(得分:1)

意识到在使用Python时你必须处理Windows Installer(COM)Automation接口。这意味着您必须自己进行所有数据库连接,查询和处理。

如果您可以转到C#(或说PowerShell),您可以利用Windows Installer XML(WiX)部署工具基础(DTF)中存在的某些更高级别的类。

using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Deployment.WindowsInstaller.Package;

static void FindAndExtractFiles(string packagePath, string longFileName)
{
    using (var installPackage = new InstallPackage(packagePath, DatabaseOpenMode.ReadOnly))
    {
        if(installPackage.FindFiles(longFileName).Count() > 0 )
            installPackage.ExtractFiles();
    }
}

您也可以将其写为ComVisible(True)并从Python调用它。

答案 2 :(得分:0)

MSI API本质上是笨重的,所以它只是抽象所在的问题。请记住,如果您只需要几次,则可以更轻松地在资源管理器中手动浏览cab文件。 (文件由文件密钥而不是文件名存储。)