0

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?

James Kent
  • 5,763
  • 26
  • 50
  • Sorry, I don't understand where exactly the actual behavior with your setup file differs from the expected behavior. Do you see the DLL at the expected location in the installation directory after the installer has finished execution? – jpeg Nov 12 '18 at 14:03
  • Have you looked at this question: https://stackoverflow.com/q/8822223/8516269? – jpeg Nov 12 '18 at 14:24
  • the issue is that the DLL has to be registered with a custom command line parameter which is used for licensing purposes, that is why I cannot record what happens to the registry during installation and make it part of the MSI as its unique per computer. as for that question unfortunately the error I get is error 3, i.e. the file is not found when the command is run – James Kent Nov 12 '18 at 15:48
  • also because of the error the installation does not complete. if I remove the custom action then yes I do see the DLL in the expected location, but for some reason it does not exist at the time the command is run, and because it must be executed as admin it must also be run before InstallFinalize – James Kent Nov 12 '18 at 15:49
  • Then I'm afraid I cannot help further. It seems that self-registration with regsvr32 is not considered to be best-practice and is only partially supported by MSI. You might need to use more customizable MSI tools, see e.g. [this post](https://stackoverflow.com/a/6141538/8516269). I've also succesfully used [NSIS](http://nsis.sourceforge.net/Main%5FPage) for other purposes. – jpeg Nov 13 '18 at 07:53
  • @jpegThanks for your help, I'll have a look at NSIS. – James Kent Nov 13 '18 at 08:26

0 Answers0