#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.