Python 使用comtypes.client.CreateObject()后释放安装程序对象

Python 使用comtypes.client.CreateObject()后释放安装程序对象,python,comtypes,Python,Comtypes,我使用comtypes.client模块在python中编写了一个函数,该函数应该从.msi文件打开数据库,并编写一个特殊的(键、值)对。到目前为止,我的问题是,一旦调用该函数没有问题,我尝试使用os.rename() PermissionError:[WinError 32]该进程无法访问该文件,因为另一进程正在使用该文件 据我所知,我的COM对象仍在使用中,因此我无法访问该文件,函数和函数调用如下所示(显然,这非常简单,但应该可以正常工作): 编写此函数是因为以前我使用VBScript设置此

我使用
comtypes.client
模块在python中编写了一个函数,该函数应该从.msi文件打开数据库,并编写一个特殊的(键、值)对。到目前为止,我的问题是,一旦调用该函数没有问题,我尝试使用
os.rename()

PermissionError:[WinError 32]该进程无法访问该文件,因为另一进程正在使用该文件

据我所知,我的COM对象仍在使用中,因此我无法访问该文件,函数和函数调用如下所示(显然,这非常简单,但应该可以正常工作):

编写此函数是因为以前我使用VBScript设置此(键、值)对:

我会在python代码中用
os.system(cscript{VBScript}{path}{Key}{Value})
调用它,但是我希望python代码尽可能减少外部依赖性。我四处寻找一些答案,我查阅了
comtypes
文档,看看是否可以显式地释放或“解耦”我的COM对象。我尝试使用
installerCOM.Quit()
installerCOM.Exit()
,这似乎不是
WindowsInstaller.Installer
对象的选项

最后,我在前面的几篇非python(主要是C)关于StackOverflow的回答中读到,将COM对象变量设置为
null
可以解决这个问题,这在VBScript中也很清楚,但在python中使用
None
似乎不起作用。可能:

导入gc
def setInstallerAttribute(安装程序路径、属性键、属性值):
installerCOM=comtypes.client.CreateObject(“WindowsInstaller.Installer”)
installerDatabase=installerCOM.OpenDatabase(安装程序路径,1)
view=installerDatabase.OpenView(“插入到属性(属性,值)值({0}',{1}')”。格式(属性\键,属性\值))
查看。执行
installerDatabase.Commit
德尔维尤
del installerDatabase
del installerCOM
gc.collect()

您可以尝试强制对变量执行垃圾收集:
del installerDatabase
del installerCOM
,但我怀疑这是否足够。是的,这似乎可以解决问题,谢谢。我可以在21小时内奖励奖金。还有一个问题,如果我使用例如
record=view.Fetch
,我如何以任何有意义的方式输出
record
,以进行调试?对不起,我对COM对象的了解不多。也许就此开始一个新的问题。
import comtypes.client
import os, shutil

def setInstallerAttribute(installer_path, attribute_key, attribute_value):
    installerCOM = comtypes.client.CreateObject("WindowsInstaller.Installer")
    installerDatabase = installerCOM.OpenDatabase (installer_path, 1)
    view = installerDatabase.OpenView ("INSERT INTO Property (Property, Value) VALUES ('{0}', '{1}')".format(attribute_key, attribute_value))
    view.Execute
    installerDatabase.Commit
    view = None
    installerDatabase = None
    installerCOM = None

if __name__ == "__main__":
    input = '{}'.format(msi_fullapth)
    key = "Build"
    value = "test_value"
    if os.path.exists(input):
        setInstallerAttribute(input, key, value)
        os.rename(input, {some other path})
Option Explicit

Dim installer, database, view, myproperty, stdout, key

Set installer = CreateObject("WindowsInstaller.Installer")
Set database = installer.OpenDatabase (WScript.Arguments.Item(0), 1)

' Update Property'
'Set view = database.OpenView ("UPDATE Property SET Value = '" & myproperty & "' WHERE Property = 'MYPROPERTY'")'

myproperty = WScript.Arguments.Item(2)
key = WScript.Arguments.Item(1)

' Add/Insert Property'
Set view = database.OpenView ("INSERT INTO Property (Property, Value) VALUES ('" & key & "', '" & myproperty & "')")

view.Execute
database.Commit

Set database = Nothing
Set installer = Nothing
Set view = Nothing