6

I used bdist_msi from cx_freeze in the past and it works nice.

Now I need to create registry entries

Is it possible to create registry entries with bdist_msi from cx_freeze?

With the wixtools these settings were done in the past:

<!-- File extension .foostarter -->
<RegistryValue Root='HKCR' Type='string' Key='.foostarter' Value='foostarter.File' />
<RegistryValue Root='HKCR' Type='string' Key='.foostarter' Name='Content Type' 
                           Value='application/vnd.foobar-modstarter' />
<RegistryValue Root='HKCR' Key='foostarter.File\Shell\Open' Type='string' Value='Ausfuehren' />
<RegistryValue Root='HKCR' Key='foostarter.File\Shell\Open\Command' Type='string'
               Value='"[#foostarter.exe]" file "%%1"' />

<!-- protocol foostarter://... -->
<RegistryValue Root='HKCR' Key='foostarter' Type='string' Value='URL: foostarter Protocol' />
<RegistryValue Root='HKCR' Key='foostarter' Type='string' Name='URL Protocol' Value=''/>
<RegistryValue Root='HKCR' Key='foostarter\shell\open\command' Type='string' 
               Value='"[#foostarter.exe]" url "%%1"' />

<!-- start without asking -->
<RegistryValue Root='HKLM' Key='Software\Microsoft\Internet Explorer\ProtocolExecute\foostarter' 
               Name='WarnOnOpen' Value='0' Type='integer' />
guettli
  • 25,042
  • 81
  • 346
  • 663

3 Answers3

2

To which purpose do you need to create registry entries?

The cx_Freeze documentation is not complete: the bdist_msi command has more options than the currently listed ones add_to_path and upgrade_code. It has an option (kwarg) data (see the source code of cx_Freeze) which can be used to add entries to the Windows Installer database tables. See here how to let the installer create desktop or program menu shortcuts by adding entries to the Shortcut Table (key Shortcut of data) and to the Directory Table (key Directory). Similarly, you can use the key Registry to add information to the Registry Table and the key RemoveRegistry to add information to the RemoveRegistry Table, telling the installer to write information to the registry upon installing and to remove it upon uninstalling.

You can use Orca to see which entries the wixtools generate in the Registry Table and Component Table (and maybe further tables) with your settings and define exactly the same tables in your setup script and pass them to bdist_msi using data.

You can also add Properties through the Property Table (key Property), an User Interface through the InstallUISequence Table, Dialog Table, Control Table, and ControlEvent Table, and much more... See here for a list of the available keys with links to the documentation of the corresponding database tables.

For more complex purposes, you probably need to use additional tools to generate an installer after running the cx_Freeze setup script. See for example the script-based tool NSIS (Nullsoft Scriptable Install System) .

jpeg
  • 2,372
  • 4
  • 18
  • 31
  • you asked about the purpose: I need to register a new URL protocol handler: `foobar://example.com/...` – guettli Aug 06 '18 at 14:50
  • Then you might manage to add the necessary entries to the [Registery Table](https://learn.microsoft.com/en-us/windows/desktop/Msi/registry-table) (and also to the [RemoveRegistery Table](https://learn.microsoft.com/en-us/windows/desktop/Msi/removeregistry-table)) through the `data` option of the `bdist_msi` command? – jpeg Aug 07 '18 at 07:43
  • you say I need to add the entries to the registry table. Yes, of course. But how to do this with "setup.py bdist_msi". I could not find docs? – guettli Aug 07 '18 at 08:15
  • I edited my answer accordingly, I hope it is more understandable now. – jpeg Aug 07 '18 at 09:16
  • I updated the answer and added concrete values. It is sad, that the cx_freeze people do not document the features. – guettli Aug 07 '18 at 10:53
  • In the source of cx_freeze I see that mslib.add_data() gets called. This would work, but I don't have the last column of table Registry: Component external key. AFAIK I can not supply it in setup.py, since this gets created during the executing of bdist_msi. – guettli Aug 07 '18 at 13:04
  • Have you tried to look with [Orca](https://learn.microsoft.com/en-us/windows/desktop/Msi/orca-exe) (see my last edit of the answer 1 hour ago) which Component_ external key and corresponding entry in the Component Table the wixtools generate? You can then pass this information to `data` as well to let the corresponding information be created during the executing of bdist_msi. – jpeg Aug 07 '18 at 13:34
  • @jpg I looked at the msi with the python library msilib. To add a Registry entry I need to know the ComponentID, I don't have this during setup.py. I will use wix now. An other solution would be to do it in two steps: First bdist_msi, then alter the created msi file and add the registry entries. – guettli Aug 08 '18 at 06:24
  • I understand that you need a ComponentID, but I do not understand enough about Components to help further. Still, my guess is that, if the goal is reachable by only **altering** the msi, this should be possible in setup.py by adding the necessary information to one ore more database tables. You might need to use runtime-valued properties such as `TARGETDIR`, add entries to the InstallUISequence table (which requires patching `bdist_msi.add_config()`) or to look-up tables such as CompLocator. A detailed comparison of the msi before and after the alteration should reveal the necessary addition. – jpeg Aug 08 '18 at 07:56
2

I am answering my own question. I think this solution should work:

First use bdist_msi to create the msi-file.

Then alter the created msi file. You could use the python library msilib. Add an entry to the table Registry, documented here: https://learn.microsoft.com/en-us/windows/desktop/msi/registry-table

I could not use the undocumented "data" argument of cx_freeze since in setup.py, since it uses msilib.add_data() . And this methods needs the external key to a component.

I don't know this component-id during setup.py.

That's why I think you need to do this in two steps.

Above is only theory. In practice I used bdist_exe and then wix to create the msi.

Since above is only vague guessing, feedback is very welcome.

guettli
  • 25,042
  • 81
  • 346
  • 663
2

MSI - MS SQL

I am not familiar with bdist_msi. However, it is definitely possible to post-process an MSI file to add registry entries if you have the right tools to do so. I am not sure if you want this scripted and automated, or if any manual steps with an appropriate tool is OK?

As you have understood from using the python library msilib, an MSI file is really a primitive MS SQL database under the hood, and you can update it using automation and a primitive SQL dialect. See "Hotfixing MSI using WiRunSQL.vbs" below. The msilib is probably just a wrapper accessing the MSI COM API - or the down-to-the-metal Win32 C++ functions - you see how little I know about Python :-). Some context on COM vs Win32 (not important for you I think).

If you insert entries in the MSI database tables, you don't really need to know the component name generated by bdist_msi, you can insert new records in both the Component table and in the Registry table with whatever records you need (in addition to those created by bdist_msi). Then you need to also write to the FeatureComponents table to add the component to a feature. Not quite trivial, but not that bad either I guess. I don't have any sample Python code using msilib, but it sounds like you already have that? Maybe a sample using regular MSI API? Here goes:

Hotfixing MSI using WiRunSQL.vbs: There is a VBScript in the MSI SDK called WiRunSQL.vbs that can be used to insert data directly into an MSI file in a scripted fashion in a very simple fashion (just simplified SQL). I describe this briefly in this answer (bottom). If you have Visual Studio installed, just search for the VBScript file under Program Files (x86).

Easy Fix?: Could the above SQL hotfixing VBScript be all you need? It is very simple to use and to automate, and it is a Microsoft VBScript. Few other entanglements and layers of indirection.

Quick MSI Update Mockup

Sample changes to MSI (open links to MSDN to see what each column means):

Component Table: (rolling with standard Pope-Mo-GUID :-) )

MyComp, {77777777-7777-7777-7777-777777777777}, TARGETDIR, 4, MyValue

Registry Table:

MyValue, -1, Software\[Manufacturer]\[ProductName]\New_Key, Value, 1, MyComp

FeatureComponents Table:

MyFeature, MyComp


Manual Tweaks Using Tools:

I hope the above made some sort of sense. Let me spin through a few "manual" or non-scripted / non-automated alternatives:

Free Tools: There are several tools you can try. That link describes the free Orca (offical Microsoft SDK MSI viewer and editor - if you got Visual Studio installed try searching for Orca-x86_en-us.msi - under Program Files (x86) - then just install it), SuperOrca and InstEd. Those are free tools.

Commercial Tools With Free Features: There is also Advanced Installer - a commercial tool that allows some basic functionality for free. I think that includes adding a registry key entry. I just tested that it works in the full version. This tool has much better GUI than Orca or the other free tools - and updates all associated tables automagically. I am not aware of any free features in Installshield or PACE Suite - the other major commercial tools, but should you already have them available, then they can do the job easily. And a quick mention: List of major, established deployment tools.

WiX: Seeing as you appear somewhat familiar with WiX, one option would be to (re)-build the whole installer with WiX. Maybe you already do? You can decompile an existing MSI to WiX format using dark.exe. This dark.exe process is described here (section 4). You can then update the WiX XML and recompile - though this may require some black art and massage to work.


Some Links:

Stein Åsmul
  • 39,960
  • 25
  • 91
  • 164
  • Yes, using the freed edition ("Simple" project) of Advanced Installer you can create MSI packages that update or create registry values/keys. – Bogdan Mitrache Aug 09 '18 at 07:26