How to create a Python .exe with MSI Installer and Cx_freeze

This is the first part of Distributing Python Apps for Windows Desktops. This is the most basic part and this matter was discussed in a lot of websites, but my idea here is to present how I’ve created the sample program and show how to generate a simple MSI installer with the necessary DLLs to run on Windows.
 Every python executable needs C++ Runtime DLLs to run on windows. You must have heard of it as Microsoft Visual C++ Redistributable or you can find it as MSVCR. The version you will need depends on which Python version you are using.

So, what we’re going to do:

  1. Our program in python files
  2. Write a setup file for the executable
  3. Generate the MSI installer

Alright, I’m creating a stupid script that I’ve used to troll one of my friends. This will replace the function of Print Screen keys and every time the key is pressed a picture of a Doll appears. I called it Boneca (That’s portuguese for doll).

import os
import sys
import ctypes
from ctypes import wintypes
import win32con

byref = ctypes.byref
user32 = ctypes.windll.user32

1 : (win32con.VK_SNAPSHOT, 0), ####Essa Linha Pega a tecla "PRINT SCREEN"
2 : (win32con.VK_F4, win32con.MOD_WIN)

def handle_print_screen ():

def handle_win_f4 ():
user32.PostQuitMessage (0)

1 : handle_print_screen,
2 : handle_win_f4

# Registering the keys without the print
for id, (vk, modifiers) in HOTKEYS.items ():
#print "Registering id", id, "for key", vk
if not user32.RegisterHotKey (None, id, modifiers, vk):
#print "Unable to register id", id

# Executando as funções e tirando o registro das chaves depois do encerramento do programa.
msg = wintypes.MSG ()
while user32.GetMessageA (byref (msg), None, 0, 0) != 0:
if msg.message == win32con.WM_HOTKEY:
action_to_take = HOTKEY_ACTIONS.get (msg.wParam)
if action_to_take:
action_to_take ()

user32.TranslateMessage (byref (msg))
user32.DispatchMessageA (byref (msg))

for id in HOTKEYS.keys ():
user32.UnregisterHotKey (None, id)

As a reference to this code I’ve used Tim Golden’s post[1].

Basically, this code creates two shortcuts on windows, one for Print Screen that when is pressed it calls handle_print_screen function that calls boneca.jpg file. The other shortcut calls handle_win_f4 to quit the program. It doesn’t have a GUI so it makes sense.

So far, so good. It’s a very simple script but now we have to freeze our code which means we will compile the script and generate a executable containing the python interpreter, the modules and files, everything on the same place. To do that we’ll need a setup file and chose one tool to freeze our app such as py2exe, py2app, cx_freeze or pyinstaller. In this case we’ll use the cx_freeze.
from cx_Freeze import setup, Executable

name = "boneca",
version = "1.0.0",
options = {"build_exe": {
'packages': ["os","sys","ctypes","win32con"],
'include_files': ['boneca.jpg'],
'include_msvcr': True,
executables = [Executable("",base="Win32GUI")]

This is very straightforward and documented as disutils. But look, we’re using include_msvcr that will add the Microsoft Visual C++ Redistributable DLLs in your executable. It will copy the existing DLLs of your OS (if you’re using windows). That’s the only way your program will run on another Windows because it needs those DLLs. Also you can download MSVCR installer and incorporante on your own installer using Inno Setup, for instance. We’ll do this on the 3rd post.

Now, we’ll generate a MSI using the command line:

python bdist_msi

Fine, now we have a dist folder with a boneca-1.0.0-win32.msi file inside or boneca-1.0.0-amd64.msi (for x64 OS) and now you can install and use the program.

Scripts on my GitHub:

It was originally published in Portuguese.


Originally published at Fernando Alves.