Освободить объект установщика после использования comtypes.client.CreateObject()

#python #comtypes

#python #comtypes

Вопрос:

Я написал функцию на python с использованием comtypes.client модуля, функция предположительно должна открывать базу данных из файла .msi и записывать специальную пару (ключ, значение). Моя проблема до сих пор заключается в том, что после вызова функции без проблем я пытаюсь использовать os.rename() для переименования файла .msi после этого и получаю ошибку разрешения:

PermissionError: [WinError 32] The process cannot access the file because it is being used by another process

я понимаю, что мой 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})
  

Функция написана потому, что ранее я использовал VBScript для установки этой пары (ключ, значение):

 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 = '" amp; myproperty amp; "' 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 ('" amp; key amp; "', '" amp; myproperty amp; "')")

view.Execute
database.Commit

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

Я бы назвал это в своем коде на python с помощью os.system(cscript {VBScript} {path} {Key} {Value}) , однако я хочу, чтобы в моем коде на python были минимальные внешние зависимости, насколько это возможно. Я искал ответы на некоторые вопросы, я заглянул в comtypes документацию, чтобы узнать, могу ли я явно освободить или «отсоединить» мой COM-объект. Я пытался использовать installerCOM.Quit() и installerCOM.Exit() , которые, похоже, не являются параметрами для WindowsInstaller.Installer объектов.

Наконец, я прочитал в нескольких предыдущих ответах на StackOverflow, не относящихся к python (в основном C #), в которых говорилось, что установка переменных COM-объекта null на это решит проблему, это также ясно из VBScript, но, похоже, это не работает в python с None

Комментарии:

1. Вы можете попытаться принудительно собрать мусор для вашей переменной: del installerDatabase и del installerCOM , но я сомневаюсь, что этого будет достаточно.

Ответ №1:

Может быть:

 import gc
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
    del view
    del installerDatabase
    del installerCOM
    gc.collect()
  

Комментарии:

1. Да, похоже, это устраняет проблему, спасибо. Я могу назначить награду через 21 час.

2. Еще один вопрос, если я использую, например record = view.Fetch , как я могу выводить record каким-либо значимым способом для отладки?

3. Извините, я не знаю больше об объектах COM. Возможно, начните новый вопрос по SO.