I wrote a function in python using the comtypes.client
module, the function should supposedly open the database from a .msi file and write a special (key, value) pair. My issue so far is once the function is called with no problems, I try to use os.rename()
to rename the .msi file afterwards and get a permission error:
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process
what I understand is that my COM object is still in use and so I cannot access the file, The function and function calls look like (obviously this is very simplified but should look work as such):
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})
The function is written because previously I was using a VBScript to set this (key, value) pair:
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
I would call this in my python code with os.system(cscript {VBScript} {path} {Key} {Value})
, however I want minimal external dependencies as possible with my python code. I was looking around for some answers, I looked into the comtypes
documentation to see if I can explicitly release or "uncouple" my COM object. I tried using installerCOM.Quit()
and installerCOM.Exit()
which seem not be options for WindowsInstaller.Installer
Objects.
Finally, I read in several previous non-python (C# mainly) answers on StackOverflow stating that setting the COM object variables to null
would solve this, this is also clear from the VBScript but this does not seem to work in python with None
Maybe:
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()