em English, Python, windows

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 press a picture of a Doll appears. I called it Boneca (That’s Portuguese for doll).

baby-looking-like-his-doll


#boneca.py (it's portuguese for doll)
import os
import sys
import ctypes
from ctypes import wintypes
import win32con

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

HOTKEYS = {
    1 : (win32con.VK_SNAPSHOT, 0), #  "PRINT SCREEN"
    2 : (win32con.VK_F4, win32con.MOD_WIN)
}

def handle_print_screen ():
    os.startfile(os.path.join(os.path.realpath(os.path.dirname(sys.argv[0])),"boneca.jpg"))

def handle_win_f4 ():
    user32.PostQuitMessage (0)

HOTKEY_ACTIONS = {
    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
    pass
    if not user32.RegisterHotKey (None, id, modifiers, vk):
        #print "Unable to register id", id
        pass


# Calling the functions and removing from the register when quitting.
try:
    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))

finally:
    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 pressed it calls the handle_print_screen function which loads the 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 an executable containing the Python interpreter, the modules, and files, everything in the same place. To do that we’ll need a setup file and chose one tool to freeze our apps such as py2exe, py2app, cx_freeze or Pyinstaller. In this case, we’ll use the cx_freeze.


#setup.py
from cx_Freeze import setup, Executable

setup(
    name = "boneca",
    version = "1.0.0",
    options = {"build_exe": {
        'packages': ["os","sys","ctypes","win32con"],
        'include_files': ['boneca.jpg'],
        'include_msvcr': True,
    }},
    executables = [Executable("boneca.py",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 into 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 incorporate on your own installer using Inno Setup, for instance. We’ll do this in the 3rd post.

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

python setup.py 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: https://github.com/ffreitasalves/boneca

It was originally published in Portuguese.

[1]: http://timgolden.me.uk/python/win32_how_do_i/catch_system_wide_hotkeys.html

Escreva um comentário

Comentário

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.

  1. I am getting an error :
    ImportError: No module named ‘win32con’ when I run the python setup.py bdist_msi
    I searched stack overflow and Googled a lot but did not find anything reliable and helpful. I am using Python 3.6 on a Windows 10.

    Just wondering can you kindly shed light on this. Thanks a bunch.

    • I have no clue… By the time this article was written I was using Python 2. But I think it can be something related to the MSVCR that Python needs to run on Windows machines, or maybe Windows 10 doesn’t have win32 anymore… Sorry, man…

Webmentions

  • Distributing Python Apps for Windows Desktops - Fernando Alves dezembro 13, 2017

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

  • How to create an MSI installer using Inno Setup - Fernando Alves dezembro 13, 2017

    […] How to create a Python.exe with MSI Installer and CX_freeze […]

  • How to create an application with auto-update using Python and Esky - Fernando Alves dezembro 13, 2017

    […] This is the 2nd part of  Distributing Python Apps for Windows Desktops series. The 1st part is here: How to create a Python .exe with MSI Installer and CX_freeze […]