callback - Python ctypes - PyMsiInterop(Windows Installer support) for Python -
i using wxpython create installation bootstraper installs multiple installations have utilize msisetexternalui of windows installer(msi.dll) progress message , pass message ui during every installation
i windows error below
create argument 1: valueerror: invalid string pointer 0x0c000000 traceback (most recent phone call last): file "msi_test.py", line 100, in <module> ret = msi.msiinstallproductw(msifile, cmdline) windowserror: exception: access violation writing 0x0c000068 my python code :
import time ctypes import * # define python-defined callback function receive installing msg msisetexternalui # has parse received msg , find out usable msg pass python ui in future def myinstallerhandler(pvcontext=none, imessagetype=none, szmessage=none) : # print of info msg t = time.time() sztime = time.strftime('%y-%m-%d %h:%m:%s', time.localtime(t)) print sztime + " :: " + str(pvcontext) print sztime + " :: myinstallerhandler ::" + str(imessagetype) + ";"+ str(szmessage) # load msi.dll print "load msi.dll" msi = windll('msi.dll') print "define functions interface of ctypes " # define ctypes interface msisetinternalui of msi.dll msi.msisetinternalui.argtypes = (c_uint, pointer(c_void_p)) msi.msisetinternalui.restype = c_int # define ctypes callback interface callback_type = winfunctype(c_int, c_uint, c_wchar_p) # define ctypes interface msisetexternaluiw of msi.dll # , assign python callback reference msisetexternalui's callback function msi.msisetexternaluiw.argtypes = (callback_type, c_ulong, c_void_p) msi.msisetexternaluiw.restype = c_int # define ctypes interface msiinstallproductw of msi.dll msi.msiinstallproductw.argtypes = (c_char_p, c_char_p) msi.msiinstallproductw.restype = c_int # define constant print "define constant : installuilevel " # installuilevel installuilevel_none = 2 installuilevel_sourceresonly = 256 print "define constant : installmessage " # installmessage installmessage_fatalexit = 0 installmessage_error = 0x01000000 installmessage_warning = 0x02000000 installmessage_user = 0x03000000 installmessage_info = 0x04000000 installmessage_filesinuse = 0x05000000 installmessage_resolvesource = 0x06000000 installmessage_outofdiskspace = 0x07000000 installmessage_actionstart = 0x08000000 installmessage_actiondata = 0x09000000 installmessage_progress = 0x0a000000 installmessage_commondata = 0x0b000000 installmessage_initialize = 0x0c000000 installmessage_terminate = 0x0d000000 installmessage_showdialog = 0x0e000000 print "define constant : installlogmode " # installlogmode installlogmode_fatalexit = (1 << (installmessage_fatalexit >> 24)) installlogmode_error = (1 << (installmessage_error >> 24)) installlogmode_warning = (1 << (installmessage_warning >> 24)) installlogmode_user = (1 << (installmessage_user >> 24)) installlogmode_info = (1 << (installmessage_info >> 24)) installlogmode_resolvesource = (1 << (installmessage_resolvesource >> 24)) installlogmode_outofdiskspace = (1 << (installmessage_outofdiskspace >> 24)) installlogmode_actionstart = (1 << (installmessage_actionstart >> 24)) installlogmode_actiondata = (1 << (installmessage_actiondata >> 24)) installlogmode_commondata = (1 << (installmessage_commondata >> 24)) installlogmode_propertydump = (1 << (installmessage_progress >> 24)) installlogmode_verbose = (1 << (installmessage_initialize >> 24)) installlogmode_extradebug = (1 << (installmessage_terminate >> 24)) installlogmode_progress = (1 << (installmessage_progress >> 24)) installlogmode_initialize = (1 << (installmessage_initialize >> 24)) installlogmode_terminate = (1 << (installmessage_terminate >> 24)) installlogmode_showdialog = (1 << (installmessage_showdialog >> 24)) # implementf installation processing # turn off default msi ui msi.msisetinternalui(installuilevel_none|installuilevel_sourceresonly, none); # assign python-defined function ctypes callback interface mypycallbackfunc = callback_type(myinstallerhandler) # create reference until procesing end installlogmode_all = installlogmode_progress|installlogmode_fatalexit|installlogmode_error|installlogmode_warning|installlogmode_user|installlogmode_info|installlogmode_resolvesource|installlogmode_outofdiskspace|installlogmode_actionstart|installlogmode_actiondata|installlogmode_commondata|installlogmode_progress|installlogmode_initialize|installlogmode_terminate|installlogmode_showdialog szmsg = "msi setexternalui test" msi.msisetexternaluiw(mypycallbackfunc, installlogmode_all, szmsg) # launch msi installing print "launch installproduct" msifile = 'd:\\mdxsetup_layout\\msisetexternui\\msisetexternui.msi' cmdline = none ret = msi.msiinstallproductw(msifile, cmdline) # close msi.dll print "release msi.dll" del msi i utilize python 2.7
any help much appreciated
thanks in advance
m.chou
---------- 2014/07/02 update --------
it worked temporarily when using english language path of msi file only. modified 2 parts , more logging in code
part 1 : callback prototype wrong @eryksun said should callback_type = winfunctype(c_int, c_int, c_uint, c_wchar_p)
part 2 : utilize msiinstallproducta(ansi) instead of msiinstallproductw(unicode).
there problem msiinstallproducta english language path of msi file only.
it failed run installing error shows msi file not found , found msi file path unreadable characters in msi log if utilize msiinstallproductw , though msi path pure english language path
i have no thought how solve now.
m.chou
----------------- code -----------------------
#!/usr/bin/env python # -*- coding: utf-8 -*- #----------------------------------------------------------------- # pymsiinterop # purpose : installing detail info while insatlling msi file # windows installer support. # auther : morris c.j chou (2014/06/26) # version : #----------------------------------------------------------------- import time, os ctypes import * import logging import re import msilib # msi message output logfile logfile = 'd:\\pymsiinterop-3.log' logging.basicconfig(filename=logfile, level=logging.debug) # define python-defined callback function receive installing msg msisetexternalui # has parse received msg , find out usable msg pass python ui in future def myinstallerhandler(pvcontext=none, imessagetype=none, szmessage=none) : # print of info msg nresult = 0 intprogressstep = none t = time.time() sztime = time.strftime('%y-%m-%d %h:%m:%s', time.localtime(t)) print sztime + " :: " + str(pvcontext) logging.debug(sztime + " :: pvcontext = " + str(pvcontext)) if imessagetype == installmessage_actiondata : print sztime + " :: installmessage_actiondata ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installmessage_actiondata ::" + str(imessagetype) + ";"+ str(szmessage)) elif imessagetype == installmessage_progress : print sztime + " :: installmessage_progress ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installmessage_progress ::" + str(imessagetype) + ";"+ str(szmessage)) ret = parseprogressstep(imessagetype, szmessage) if ret[0] == true : intprogressstep = ret[1] elif imessagetype == installmessage_actionstart : print sztime + " :: installmessage_actionstart ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installmessage_actionstart ::" + str(imessagetype) + ";"+ str(szmessage)) elif imessagetype == installmessage_commondata : print sztime + " :: installmessage_commondata ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installmessage_commondata ::" + str(imessagetype) + ";"+ str(szmessage)) elif imessagetype == installmessage_error : print sztime + " :: installmessage_error ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installmessage_error ::" + str(imessagetype) + ";"+ str(szmessage)) elif imessagetype == installmessage_fatalexit : print sztime + " :: installmessage_fatalexit ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installmessage_fatalexit ::" + str(imessagetype) + ";"+ str(szmessage)) elif imessagetype == installmessage_filesinuse : print sztime + " :: installmessage_filesinuse ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installmessage_filesinuse ::" + str(imessagetype) + ";"+ str(szmessage)) elif imessagetype == installmessage_info : print sztime + " :: installmessage_info ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installmessage_info ::" + str(imessagetype) + ";"+ str(szmessage)) elif imessagetype == installmessage_initialize : print sztime + " :: installmessage_initialize ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installmessage_initialize ::" + str(imessagetype) + ";"+ str(szmessage)) elif imessagetype == installmessage_outofdiskspace : print sztime + " :: installmessage_outofdiskspace ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installmessage_outofdiskspace ::" + str(imessagetype) + ";"+ str(szmessage)) elif imessagetype == installmessage_resolvesource : print sztime + " :: installmessage_resolvesource ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installmessage_resolvesource ::" + str(imessagetype) + ";"+ str(szmessage)) elif imessagetype == installlogmode_showdialog : print sztime + " :: installlogmode_showdialog ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installlogmode_showdialog ::" + str(imessagetype) + ";"+ str(szmessage)) elif imessagetype == installmessage_terminate : print sztime + " :: installmessage_terminate ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installmessage_terminate ::" + str(imessagetype) + ";"+ str(szmessage)) elif imessagetype == installlogmode_user : print sztime + " :: installlogmode_user ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installlogmode_user ::" + str(imessagetype) + ";"+ str(szmessage)) elif imessagetype == installmessage_warning : print sztime + " :: installmessage_warning ::" + str(imessagetype) + ";"+ str(szmessage) logging.debug(sztime + " :: installmessage_warning ::" + str(imessagetype) + ";"+ str(szmessage)) # send installing detali progress value , msg ui #if (szinstallmsg <> none) or (intprogressstep <> none) : #sendprogressmsgtoui(ui_signal, intprogressstep, szinstallmsg) #pass homecoming nresult def loginstallmsg() : pass def parseinstallmsg(imessagetype, szmessage) : # filter out useful msg pass ui # e.g. installmessage_actiondata ::150994944;file: teapot.ppm, directory: c:\program files\molding\my product name\tcl\tk8.5\demos\images\, size: 196623 # imessagetype = 150994944 # szmessage = file: teapot.ppm, directory: c:\program files\molding\my product name\tcl\tk8.5\demos\images\, size: 196623 nresult = 0 homecoming nresult, szinstallmsg def parseprogressstep(imessagetype, szmessage) : # e.g. installmessage_progress ::167772160;1: 2 2: 32768 3: 0 4: 0 # imessagetype = 167772160 # szmessage = 1: 2 2: 32768 3: 0 4: 0 nresult = false intprogressstep = none if szmessage <> "" : pattern = '2:\s\d+' match = re.search(pattern,szmessage) szstring = match.group() # szstring = '2: 32768' pattern = '\s\d+' match = re.search(pattern,szstring) szstep = match.group().strip() # szstring = '32768' intprogressstep = int(szstep) nresult = true logging.debug("installmessage_progress :: intprogressstep = " + str(intprogressstep)) homecoming nresult, intprogressstep #---------------------------------------------------------------------- # getrequiredsizefrommsi(self, msi_path): # input : msi file path # homecoming : required size #---------------------------------------------------------------------- def getrequiredsizefrommsi(self, msi_path): total_size = 0 if os.path.exists(msi_path) == true : db = msilib.opendatabase(msi_path, msilib.msidbopen_readonly) #view = db.openview("select filename, filesize file component_ in ('component_1', 'component_2')") view = db.openview("select filename, filesize file") view.execute(none) =0 while true: seek : record = view.fetch() += 1 if not record: break else : print str(i) + " : " + record.getstring(1), record.getstring(2) logging.debug("getrequiredsizefrommsi :: file:" + record.getstring(1) + " size:" + record.getstring(2)) total_size += int(record.getstring(2)) except : break print total_size logging.debug("getrequiredsizefrommsi :: required space size : " + str(total_size)) homecoming total_size def sendprogressmsgtoui(ui_signal, progresspercent, progressmsg) : pass # load msi.dll print "load msi.dll" msi = windll('msi.dll') print "define functions interface of ctypes " # define ctypes interface msisetinternalui of msi.dll msi.msisetinternalui.argtypes = (c_uint, pointer(c_void_p)) msi.msisetinternalui.restype = c_int # define ctypes callback interface callback_type = winfunctype(c_int, c_int, c_uint, c_wchar_p) # define ctypes interface msisetexternaluiw of msi.dll # , assign python callback reference msisetexternalui's callback function msi.msisetexternaluiw.argtypes = (callback_type, c_ulong, c_void_p) msi.msisetexternaluiw.restype = c_int # define ctypes interface msiinstallproductw of msi.dll msi.msiinstallproducta.argtypes = (c_char_p, c_char_p) msi.msiinstallproducta.restype = c_int # define constant print "define constant : installuilevel " # installuilevel installuilevel_none = 2 installuilevel_sourceresonly = 256 print "define constant : installmessage " # installmessage installmessage_fatalexit = 0 installmessage_error = 0x01000000 installmessage_warning = 0x02000000 installmessage_user = 0x03000000 installmessage_info = 0x04000000 installmessage_filesinuse = 0x05000000 installmessage_resolvesource = 0x06000000 installmessage_outofdiskspace = 0x07000000 installmessage_actionstart = 0x08000000 installmessage_actiondata = 0x09000000 installmessage_progress = 0x0a000000 installmessage_commondata = 0x0b000000 installmessage_initialize = 0x0c000000 installmessage_terminate = 0x0d000000 installmessage_showdialog = 0x0e000000 print "define constant : installlogmode " # installlogmode installlogmode_fatalexit = (1 << (installmessage_fatalexit >> 24)) installlogmode_error = (1 << (installmessage_error >> 24)) installlogmode_warning = (1 << (installmessage_warning >> 24)) installlogmode_user = (1 << (installmessage_user >> 24)) installlogmode_info = (1 << (installmessage_info >> 24)) installlogmode_resolvesource = (1 << (installmessage_resolvesource >> 24)) installlogmode_outofdiskspace = (1 << (installmessage_outofdiskspace >> 24)) installlogmode_actionstart = (1 << (installmessage_actionstart >> 24)) installlogmode_actiondata = (1 << (installmessage_actiondata >> 24)) installlogmode_commondata = (1 << (installmessage_commondata >> 24)) installlogmode_propertydump = (1 << (installmessage_progress >> 24)) installlogmode_verbose = (1 << (installmessage_initialize >> 24)) installlogmode_extradebug = (1 << (installmessage_terminate >> 24)) installlogmode_progress = (1 << (installmessage_progress >> 24)) installlogmode_initialize = (1 << (installmessage_initialize >> 24)) installlogmode_terminate = (1 << (installmessage_terminate >> 24)) installlogmode_showdialog = (1 << (installmessage_showdialog >> 24)) installlogmode_all = installlogmode_progress|installlogmode_fatalexit|installlogmode_error|installlogmode_warning|installlogmode_user|installlogmode_info|installlogmode_resolvesource|installlogmode_outofdiskspace|installlogmode_actionstart|installlogmode_actiondata|installlogmode_commondata|installlogmode_initialize|installlogmode_terminate|installlogmode_showdialog # implementf installation processing # turn off default msi ui msi.msisetinternalui(installuilevel_none|installuilevel_sourceresonly, none); # assign python-defined function ctypes callback interface mypycallbackfunc = callback_type(myinstallerhandler) # create reference until procesing end szmsg = "msi setexternalui test" msi.msisetexternaluiw(mypycallbackfunc, installlogmode_all, szmsg) # launch msi installing print "launch installproduct" msifile = 'd:\\mdxsetup_layout\\msisetexternui\\msisetexternui.msi' cmdline = '' #print msifile #print msifile.decode('utf-8') #ret = msi.msiinstallproductw(msifile.decode('utf-8'), cmdline) ret = msi.msiinstallproducta(msifile, cmdline) print ret # close msi.dll print "release msi.dll" del msi python-2.7 callback windows-installer ctypes
No comments:
Post a Comment