I have a package I'm trying to wrap in an MSI that requires a DLL to be registered with command line parameters after install. using cx_Freeze I can add a custom action and add it to the execute sequence to be run during installation, however no matter where in the sequence I put it the command fails unless I copy the files to the target install directory before running the installer.
my setup file is:
#!python3
import os, sys, shutil, platform
from cx_Freeze import setup
command_line = 'regsvr32.exe /s /i:"stuff_here" MyDLL.dll'
files = ['MyDLL.dll']
if platform.architecture()[0] == '32bit':
builddir = 'build/bdist.win32/msi'
else:
builddir = 'build/bdist.win-amd64/msi'
os.makedirs(builddir, exist_ok=True)
for file in files:
shutil.copyfile(file, os.path.join(builddir, file))
if 'bdist_msi' in sys.argv:
sys.argv += ['--initial-target-dir', '[ProgramFilesFolder]DLL_Thing']
custom_action_table = []
if command_line != '':
custom_action_table.append(
# action to take to register DLL
(
'RegisterDLLs', # action key name
34, # type (EXE file having a path referencing a directory.)
'TARGETDIR', #
command_line, # command line
),
)
install_execute_sequence_table = []
if command_line != '':
install_execute_sequence_table.append(
# call regsvr after rest of product finishes installing.
(
'RegisterDLLs', # action key name
None, # condition
6501, # sequence
),
)
# Change some default MSI options and specify the use of the above defined tables
bdist_msi_options = {
'data': {
'CustomAction': custom_action_table,
'InstallExecuteSequence': install_execute_sequence_table
},
}
setup( name = 'DLL Thing',
version = '1.0.0',
description = 'DLL Thing',
options = {'build_exe': {'include_files': files}, 'bdist_msi': bdist_msi_options,},
)
reading through my installseqeuence table:
LaunchConditions 100
FindRelatedProducts 200
AppSearch 400
A_SET_TARGET_DIR TARGETDIR="" 401
CCPSearch NOT Installed 500
RMCCPSearch NOT Installed 600
ValidateProductID 700
CostInitialize 800
FileCost 900
IsolateComponents 950
CostFinalize 1000
SetODBCFolders 1100
MigrateFeatureStates 1200
InstallValidate 1400
RemoveExistingProducts 1450
InstallInitialize 1500
AllocateRegistrySpace NOT Installed 1550
ProcessComponents 1600
UnpublishComponents 1700
MsiUnpublishAssemblies 1750
UnpublishFeatures 1800
StopServices VersionNT 1900
DeleteServices VersionNT 2000
UnregisterComPlus 2100
SelfUnregModules 2200
UnregisterTypeLibraries 2300
RemoveODBC 2400
UnregisterFonts 2500
RemoveRegistryValues 2600
UnregisterClassInfo 2700
UnregisterExtensionInfo 2800
UnregisterProgIdInfo 2900
UnregisterMIMEInfo 3000
RemoveIniValues 3100
RemoveShortcuts 3200
RemoveEnvironmentStrings 3300
RemoveDuplicateFiles 3400
RemoveFiles 3500
RemoveFolders 3600
CreateFolders 3700
MoveFiles 3800
InstallFiles 4000
PatchFiles 4090
DuplicateFiles 4210
BindImage 4300
CreateShortcuts 4500
RegisterClassInfo 4600
RegisterExtensionInfo 4700
RegisterProgIdInfo 4800
RegisterMIMEInfo 4900
WriteRegistryValues 5000
WriteIniValues 5100
WriteEnvironmentStrings 5200
RegisterFonts 5300
InstallODBC 5400
RegisterTypeLibraries 5500
SelfRegModules 5600
RegisterComPlus 5700
InstallServices VersionNT 5800
StartServices VersionNT 5900
RegisterUser 6000
RegisterProduct 6100
PublishComponents 6200
MsiPublishAssemblies 6250
PublishFeatures 6300
PublishProduct 6400
RegisterDLLs 6501
InstallFinalize 6600
the files should be installed at sequence 4000, yet at 6501 when I try to register the DLL the files do not yet appear on disk (using sysinternals procmon I can see that the error raised is due to the file not being found)
if I try run after the finalize stage (6601) then the installer has dropped the admin privileges and cannot register the dll.
how can I achieve my desired result?