Index: MANIFEST.in
===================================================================
--- MANIFEST.in	(revision 916)
+++ MANIFEST.in	(revision 939)
@@ -1,5 +1,4 @@
 include mlx.nsi
-include makeinst.bat
-include winemakeinst.bat
+include makeinst.sh
 include license.txt
 include runmlx.py
Index: dcdatagen.py
===================================================================
--- dcdatagen.py	(revision 599)
+++ dcdatagen.py	(revision 932)
@@ -1,3 +1,3 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
@@ -764,12 +764,12 @@
     numLines = len(lines)
     if numLines==0:
-        print >> file, "msgstr \"\""
+        print("msgstr \"\"", file=file)
     elif numLines==1:
-        print >> file, "msgstr \"%s\"" % (lines[0])
+        print("msgstr \"%s\"" % (lines[0]), file=file)
     else:
-        print >> file, "msgstr \"\""
+        print("msgstr \"\"", file=file)
         for i in range(0, numLines):
-            print >> file, "\"%s%s\"" % (lines[i], "" if i==(numLines-1) else "\\n")
-    print >> file
+            print("\"%s%s\"" % (lines[i], "" if i==(numLines-1) else "\\n"), file=file)
+    print(file=file)
 
 #-------------------------------------------------------------------------------
@@ -789,8 +789,8 @@
             poFile = open(poPath, "wt")
             poFiles.append(poFile)
-            print >> poFile, "msgid \"\""
-            print >> poFile, "msgstr \"\""
-            print >> poFile, "\"Content-Type: text/plain; charset=utf-8\\n\""
-            print >> poFile, "\"Content-Transfer-Encoding: 8bit\\n\""
+            print("msgid \"\"", file=poFile)
+            print("msgstr \"\"", file=poFile)
+            print("\"Content-Type: text/plain; charset=utf-8\\n\"", file=poFile)
+            print("\"Content-Transfer-Encoding: 8bit\\n\"", file=poFile)
 
         (baseData, headings, headingFlags, rows) = table
@@ -801,5 +801,5 @@
             for j in range(0, numLanguages):
                 poFile = poFiles[j]
-                print >> poFile, "msgid \"%sheading%d\"" % (poPrefix, i)
+                print("msgid \"%sheading%d\"" % (poPrefix, i), file=poFile)
                 generateMsgStr(poFile, heading[j])
 
@@ -810,5 +810,5 @@
                 for i in range(0, numLanguages):
                     poFile = poFiles[i]
-                    print >> poFile, "msgid \"%srow%d\"" % (poPrefix, rowIndex)
+                    print("msgid \"%srow%d\"" % (poPrefix, rowIndex), file=poFile)
                     generateMsgStr(poFile, columns[i])
             elif type==DELAYCODE:
@@ -819,20 +819,20 @@
                             if column[i]:
                                 poFile = poFiles[i]
-                                print >> poFile, "msgid \"%srow%d_col%d\"" % \
-                                  (poPrefix, rowIndex, columnIndex)
+                                print("msgid \"%srow%d_col%d\"" % \
+                                  (poPrefix, rowIndex, columnIndex), file=poFile)
                                 generateMsgStr(poFile, column[i])
                     columnIndex += 1
             rowIndex += 1
 
-        print >> dcdata, "import mlx.const as const"
-        print >> dcdata, "from mlx.i18n import xstr"
-        print >> dcdata
-        print >> dcdata, "CAPTION = 1"
-        print >> dcdata, "DELAYCODE = 2"
-        print >> dcdata
+        print("import mlx.const as const", file=dcdata)
+        print("from mlx.i18n import xstr", file=dcdata)
+        print(file=dcdata)
+        print("CAPTION = 1", file=dcdata)
+        print("DELAYCODE = 2", file=dcdata)
+        print(file=dcdata)
 
         tableMask = 1
         for i in range(0, len(tablePrefixes)):
-            print >> dcdata, "_%s_code2meaning = {" % (tablePrefixes[i],)
+            print("_%s_code2meaning = {" % (tablePrefixes[i],), file=dcdata)
 
             columnIndexes = []
@@ -850,25 +850,25 @@
 
                 if type==DELAYCODE:
-                    print >> dcdata, "    \"%s\": \"%s\"," % \
-                      (str(columns[codeIndex]).strip(), columns[meaningIndex][0].replace("\n", ""))
-
-            print >> dcdata, "}"
-            print >> dcdata
+                    print("    \"%s\": \"%s\"," % \
+                      (str(columns[codeIndex]).strip(), columns[meaningIndex][0].replace("\n", "")), file=dcdata)
+
+            print("}", file=dcdata)
+            print(file=dcdata)
 
             tableMask <<= 1
 
-        print >> dcdata, "def _extract(table, row):"
-        print >> dcdata, "    code = row[0].strip()"
-        print >> dcdata, "    meaning = table[code] if code in table else None"
-        print >> dcdata, "    return code + ((\" (\" + meaning + \")\") if meaning else \"\")"
-        print >> dcdata
+        print("def _extract(table, row):", file=dcdata)
+        print("    code = row[0].strip()", file=dcdata)
+        print("    meaning = table[code] if code in table else None", file=dcdata)
+        print("    return code + ((\" (\" + meaning + \")\") if meaning else \"\")", file=dcdata)
+        print(file=dcdata)
 
         tableMask = 1
         for i in range(0, len(tablePrefixes)):
 
-            print >> dcdata, "_%s_data = (" % (tablePrefixes[i],)
-            print >> dcdata, "    lambda row: _extract(_%s_code2meaning, row)," % \
-              (tablePrefixes[i],)
-            print >> dcdata, "    [",
+            print("_%s_data = (" % (tablePrefixes[i],), file=dcdata)
+            print("    lambda row: _extract(_%s_code2meaning, row)," % \
+              (tablePrefixes[i],), file=dcdata)
+            print("    [", end=' ', file=dcdata)
 
             columnIndexes = []
@@ -876,11 +876,11 @@
                 if ( (headingFlags[j]&tableMask)==tableMask ):
                     if columnIndexes:
-                        print >> dcdata, ",",
-                    print >> dcdata, "xstr(\"%sheading%d\")" % (poPrefix, j),
+                        print(",", end=' ', file=dcdata)
+                    print("xstr(\"%sheading%d\")" % (poPrefix, j), end=' ', file=dcdata)
                     columnIndexes.append(j)
 
-            print >> dcdata, "],"
-
-            print >> dcdata, "    ["
+            print("],", file=dcdata)
+
+            print("    [", file=dcdata)
 
             rowIndex = 0
@@ -891,43 +891,43 @@
 
                 if type==CAPTION:
-                    print >> dcdata, "        (CAPTION, xstr(\"%srow%d\"))," % \
-                      (poPrefix, rowIndex)
+                    print("        (CAPTION, xstr(\"%srow%d\"))," % \
+                      (poPrefix, rowIndex), file=dcdata)
                 elif type==DELAYCODE:
-                    print >> dcdata, "        (DELAYCODE, ["
+                    print("        (DELAYCODE, [", file=dcdata)
                     for j in columnIndexes:
                         column = columns[j]
                         if j!=columnIndexes[0]:
-                            print >> dcdata, ","
+                            print(",", file=dcdata)
                         if isinstance(column, list):
                             if column[0]:
-                                print >> dcdata, "            xstr(\"%srow%d_col%d\")"  % \
-                                (poPrefix, rowIndex, j),
+                                print("            xstr(\"%srow%d_col%d\")"  % \
+                                (poPrefix, rowIndex, j), end=' ', file=dcdata)
                             else:
-                                print >> dcdata, "            \"\"",
+                                print("            \"\"", end=' ', file=dcdata)
                         else:
-                            print >> dcdata, "            \"%s\""  % \
-                              (column,),
-                    print >> dcdata, "] ),"
+                            print("            \"%s\""  % \
+                              (column,), end=' ', file=dcdata)
+                    print("] ),", file=dcdata)
                 rowIndex += 1
 
-            print >> dcdata, "    ]"
-
-            print >> dcdata, ")"
-            print >> dcdata
+            print("    ]", file=dcdata)
+
+            print(")", file=dcdata)
+            print(file=dcdata)
 
             tableMask <<= 1
 
-        print >> dcdata, "def getTable(aircraftType):"
+        print("def getTable(aircraftType):", file=dcdata)
         first = True
         for i in range(0, len(tablePrefixes)):
             tablePrefix = tablePrefixes[i]
             for typeSuffix in typeGroups[i]:
-                print >> dcdata, "    %s aircraftType==const.AIRCRAFT_%s:" % \
-                  ("if" if first else "elif", typeSuffix)
-                print >> dcdata, "        return _%s_data" % (tablePrefix,)
+                print("    %s aircraftType==const.AIRCRAFT_%s:" % \
+                  ("if" if first else "elif", typeSuffix), file=dcdata)
+                print("        return _%s_data" % (tablePrefix,), file=dcdata)
                 first = False
 
-        print >> dcdata, "    else:"
-        print >> dcdata, "        return None"
+        print("    else:", file=dcdata)
+        print("        return None", file=dcdata)
     finally:
         for poFile in poFiles:
Index: diffdist.py
===================================================================
--- diffdist.py	(revision 310)
+++ diffdist.py	(revision 919)
@@ -18,5 +18,5 @@
 def usage():
     """Print a usage message."""
-    print "Usage: %s <old dist dir> <new dist dir>" % (sys.argv[0],)
+    print("Usage: %s <old dist dir> <new dist dir>" % (sys.argv[0],))
 
 #--------------------------------------------------------------------------
@@ -62,11 +62,11 @@
 
                 if numDiffs<=4:
-                    print "File %s is considered to be the same in both versions with %d changes" % \
-                          (path, numDiffs)
+                    print("File %s is considered to be the same in both versions with %d changes" % \
+                          (path, numDiffs))
                     finalManifest.addFile(path, oldSize, oldSum)
                     copyOld = True
 
         if not copyOld:
-            print ">>> File %s is being copied" % (path,)
+            print(">>> File %s is being copied" % (path,))
             tarFile.add(os.path.join(newDirectory, path), arcname = path)
             
@@ -74,5 +74,5 @@
     with os.fdopen(fd, "wt") as f:
         finalManifest.writeInto(f)
-    os.chmod(path, 0644)
+    os.chmod(path, 0o644)
     tarFile.add(path, arcname = manifestName)
     tarFile.close()
@@ -80,10 +80,10 @@
     os.remove(path)
 
-    print
-    print "%s created" % (tarName,)
+    print()
+    print("%s created" % (tarName,))
     if removed:
-        print
-        print "Files to remove:"
-        print
+        print()
+        print("Files to remove:")
+        print()
         for path in removed:
-            print "  ", path
+            print("  ", path)
Index: docker/build-mlxwinebuild.sh
===================================================================
--- docker/build-mlxwinebuild.sh	(revision 916)
+++ docker/build-mlxwinebuild.sh	(revision 939)
@@ -6,4 +6,4 @@
 sdistdir=$(cd $(dirname "${sdistfile}") && pwd)
 
-docker run --rm -v "${sdistdir}:/root/dist" mlxwinebuild build $(basename "${sdistfile}") $(id -u) $(id -g)
-#docker run -it --rm -v "${sdistdir}:/root/dist" mlxwinebuild bash
+docker run --rm -v "${sdistdir}:/root/dist" mlxwinebuild-py3 build $(basename "${sdistfile}") $(id -u) $(id -g)
+#docker run -it --rm -v "${sdistdir}:/root/dist" mlxwinebuild-py3 bash
Index: docker/context/Dockerfile
===================================================================
--- docker/context/Dockerfile	(revision 916)
+++ docker/context/Dockerfile	(revision 939)
@@ -8,4 +8,5 @@
         wine \
         wine32 && \
+    apt-get clean && \
     echo "Europe/Budapest" > /etc/timezone && \
     rm -f /etc/localtime && \
Index: docker/context/build.sh
===================================================================
--- docker/context/build.sh	(revision 916)
+++ docker/context/build.sh	(revision 939)
@@ -18,5 +18,6 @@
 cd "${mlxdirname}"
 
-echo "winemakeinst.bat" | wine cmd
+export WINE=yes
+./makeinst.sh
 
 echo
Index: docker/context/setup.sh
===================================================================
--- docker/context/setup.sh	(revision 916)
+++ docker/context/setup.sh	(revision 939)
@@ -4,9 +4,7 @@
 
 cdrive="${HOME}/.wine/drive_c"
-ctmpdir="${cdrive}/tmp"
-cpythondir="${cdrive}/Python27"
-cwinsysdir="${cdrive}/windows/system32"
+cpythondir="${cdrive}/msys64/mingw32"
 
-if test -f "${cpythondir}/python.exe"; then
+if test -f "${cpythondir}/bin/python3.exe"; then
     echo "Image already configured, not doing anything!"
     exit 1
@@ -16,37 +14,23 @@
 echo
 
+export WINEARCH=win32
+
+echo "exit" | wine cmd
+
 echo "Downloading and extracting the extra packages..."
 
-wget -O - mlx.varadiistvan.hu/update/winepkgs.tar | tar xf -
+wget -O - mlx.varadiistvan.hu/update/msys64.tar.gz | tar xzf - -C "${cdrive}"
+wget -O - mlx.varadiistvan.hu/update/winepkgs.tar | tar xf - nsis-2.46-setup.exe pyuipc-cpython-37m.dll xplra.py
+
+mv  pyuipc-cpython-37m.dll xplra.py /root/.wine/drive_c/msys64/mingw32/lib/python3.7/site-packages
 
 echo
 echo "Installing extra packages..."
 
-export WINEARCH=win32
-
-echo "exit" | wine cmd
-wine msiexec /i python-2.7.2.msi
-wine msiexec /i cefpython3-31.2.py2.7-win32.msi
-wine msiexec /i pygtk-all-in-one-2.24.1.win32-py2.7.msi
-wine msiexec /i pyuipc-0.4.win32-py2.7.msi
-wine msiexec /i xplra-0.2.win32.msi
-
-wine pywin32-217.win32-py2.7.exe
-wine py2exe-0.6.9.win32-py2.7.exe
 wine nsis-2.46-setup.exe
-
-mkdir "${ctmpdir}"
-cp chromedriver.exe "${ctmpdir}"
-
-tar xzf Python27.extra.tar.gz -C "${cpythondir}"
-
-touch -d "2015-02-22 14:50:07" "${cpythondir}/Lib/site-packages/win32/lib/win32con.py"
-touch -d "2015-02-22 14:50:07" "${cpythondir}/Lib/site-packages/win32/lib/winerror.py"
-
-cp python27.dll WINHTTP.dll "${cwinsysdir}"
 
 echo
 echo "Removing extra packages..."
-rm -f *.msi *.exe Python27.extra.tar.gz python27.dll WINHTTP.dll
+rm -f *.exe
 echo
 echo "Done."
Index: docker/initialize-mlxwinebuild.sh
===================================================================
--- docker/initialize-mlxwinebuild.sh	(revision 916)
+++ docker/initialize-mlxwinebuild.sh	(revision 939)
@@ -6,5 +6,5 @@
 scriptdir=`cd "${scriptdir}" && pwd`
 
-docker build -t mlxwinebuild-base "${scriptdir}/context"
+docker build -t mlxwinebuild-py3-base "${scriptdir}/context"
 
 if test -z "${XAUTHORITY:-}"; then
@@ -12,9 +12,9 @@
 fi
 
-docker run -it --name mlxwinebuildinit -v /tmp/.X11-unix:/tmp/.X11-unix -v "${XAUTHORITY}":/root/.Xauthority -v /usr/lib/x86_64-linux-gnu/vdpau:/usr/lib/x86_64-linux-gnu/vdpau --device /dev/nvidiactl --device /dev/nvidia0 --security-opt=apparmor:unconfined  --env DISPLAY mlxwinebuild-base initialize
+docker run -it --name mlxwinebuildinit -v /tmp/.X11-unix:/tmp/.X11-unix -v "${XAUTHORITY}":/root/.Xauthority -v /usr/lib/x86_64-linux-gnu/vdpau:/usr/lib/x86_64-linux-gnu/vdpau --device /dev/nvidiactl --device /dev/nvidia0 --security-opt=apparmor:unconfined  --env DISPLAY mlxwinebuild-py3-base initialize
 
 echo "Committing new image..."
 
-docker commit --change='CMD ["bash"]' mlxwinebuildinit mlxwinebuild
+docker commit --change='CMD ["bash"]' mlxwinebuildinit mlxwinebuild-py3
 
 echo "Removing container..."
Index: docker/msys/Dockerfile
===================================================================
--- docker/msys/Dockerfile	(revision 920)
+++ docker/msys/Dockerfile	(revision 920)
@@ -0,0 +1,25 @@
+#escape=`
+FROM mcr.microsoft.com/windows/servercore:1809
+SHELL ["powershell", "-Command"]
+
+RUN $WebClient = New-Object System.Net.WebClient ; `
+    $WebClient.DownloadFile('https://www.7-zip.org/a/7z1900-x64.msi', '7z.msi') ; `
+    $WebClient.DownloadFile('http://repo.msys2.org/distrib/msys2-x86_64-latest.tar.xz', 'msys2.tar.xz') ; `
+    Start-Process msiexec.exe -ArgumentList '/i C:\7z.msi /qn reboot=r' -Wait -PassThru -Verbose ; `
+    Start-Process 'C:\Program Files\7-Zip\7z.exe' -ArgumentList 'x msys2.tar.xz' -Wait -PassThru -Verbose ; `
+    Start-Process tar -ArgumentList 'xf msys2.tar' -Wait -PassThru -Verbose ; `
+    Start-Process msiexec.exe -ArgumentList '/x C:\7z.msi /qn reboot=r' -Wait -PassThru -Verbose ; `
+    Remove-Item msys2.tar ; `
+    Remove-Item msys2.tar.xz ; `
+    Remove-Item 7z.msi
+
+RUN $env:MSYSTEM='MINGW32' ; `
+    Start-Process C:\msys64\usr\bin\pacman.exe -ArgumentList '-Syu --noconfirm' -Wait -PassThru -Verbose -WorkingDirectory 'C:\msys64' ; `
+    Start-Process C:\msys64\usr\bin\pacman.exe -ArgumentList '-Su --noconfirm' -Wait -PassThru -Verbose -WorkingDirectory 'C:\msys64' ; `
+    Start-Process C:\msys64\usr\bin\bash.exe -ArgumentList '--login -c /usr/bin/true.exe' -Wait -PassThru -Verbose -WorkingDirectory 'C:\msys64'; `
+    mkdir C:\msys64\build
+
+COPY setup.sh pywin32.patch pywin32git.patch cef_binary_3.3359.1774.gd49d25f_windows32.patch cefpython-66.0.patch py2exe.patch C:\msys64\build\
+
+RUN $env:MSYSTEM='MINGW32'; `
+    C:\msys64\usr\bin\bash.exe --login  C:\msys64\build\setup.sh ;
Index: docker/msys/cef_binary_3.3359.1774.gd49d25f_windows32.patch
===================================================================
--- docker/msys/cef_binary_3.3359.1774.gd49d25f_windows32.patch	(revision 920)
+++ docker/msys/cef_binary_3.3359.1774.gd49d25f_windows32.patch	(revision 920)
@@ -0,0 +1,367 @@
+--- cef_binary_3.3359.1774.gd49d25f_windows32/include/internal/cef_string_wrappers.h.orig	2019-03-09 15:59:59.571378000 +0100
++++ cef_binary_3.3359.1774.gd49d25f_windows32/include/internal/cef_string_wrappers.h	2019-03-09 16:00:08.284090000 +0100
+@@ -33,6 +33,7 @@
+ 
+ #include <memory.h>
+ #include <string>
++#include <cstring>
+ 
+ #include "include/base/cef_string16.h"
+ #include "include/internal/cef_string_types.h"
+--- cef_binary_3.3359.1774.gd49d25f_windows32/include/base/cef_bind_helpers.h.orig	2018-05-17 11:46:05.000000000 +0200
++++ cef_binary_3.3359.1774.gd49d25f_windows32/include/base/cef_bind_helpers.h	2019-03-09 16:03:17.830725000 +0100
+@@ -272,12 +272,12 @@
+ // MSVC warns when you try to use Base if T has a private destructor, the
+ // common pattern for refcounted types. It does this even though no attempt to
+ // instantiate Base is made.  We disable the warning for this definition.
+-#if defined(OS_WIN)
++#if defined(OS_WIN) && defined(COMPILER_MSVC)
+ #pragma warning(push)
+ #pragma warning(disable : 4624)
+ #endif
+   struct Base : public T, public BaseMixin {};
+-#if defined(OS_WIN)
++#if defined(OS_WIN) && defined(COMPILER_MSVC)
+ #pragma warning(pop)
+ #endif
+ 
+--- cef_binary_3.3359.1774.gd49d25f_windows32/include/base/internal/cef_atomicops_x86_gcc.h.orig	2019-04-02 20:09:10.287478919 +0200
++++ cef_binary_3.3359.1774.gd49d25f_windows32/include/base/internal/cef_atomicops_x86_gcc.h	2019-04-02 20:09:10.287478919 +0200
+@@ -0,0 +1,268 @@
++// Copyright (c) 2011 Google Inc. All rights reserved.
++//
++// Redistribution and use in source and binary forms, with or without
++// modification, are permitted provided that the following conditions are
++// met:
++//
++//    * Redistributions of source code must retain the above copyright
++// notice, this list of conditions and the following disclaimer.
++//    * Redistributions in binary form must reproduce the above
++// copyright notice, this list of conditions and the following disclaimer
++// in the documentation and/or other materials provided with the
++// distribution.
++//    * Neither the name of Google Inc. nor the name Chromium Embedded
++// Framework nor the names of its contributors may be used to endorse
++// or promote products derived from this software without specific prior
++// written permission.
++//
++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++
++// Do not include this header file directly. Use base/cef_atomicops.h
++// instead.
++
++#ifndef CEF_INCLUDE_BASE_INTERNAL_CEF_ATOMICOPS_X86_GCC_H_
++#define CEF_INCLUDE_BASE_INTERNAL_CEF_ATOMICOPS_X86_GCC_H_
++
++// This struct is not part of the public API of this module; clients may not
++// use it.
++// Features of this x86.  Values may not be correct before main() is run,
++// but are set conservatively.
++struct AtomicOps_x86CPUFeatureStruct {
++  bool has_amd_lock_mb_bug;  // Processor has AMD memory-barrier bug; do lfence
++                             // after acquire compare-and-swap.
++};
++extern struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures;
++
++#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
++
++namespace base {
++namespace subtle {
++
++// 32-bit low-level operations on any platform.
++
++inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
++                                         Atomic32 old_value,
++                                         Atomic32 new_value) {
++  Atomic32 prev;
++  __asm__ __volatile__("lock; cmpxchgl %1,%2"
++                       : "=a"(prev)
++                       : "q"(new_value), "m"(*ptr), "0"(old_value)
++                       : "memory");
++  return prev;
++}
++
++inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
++                                         Atomic32 new_value) {
++  __asm__ __volatile__("xchgl %1,%0"  // The lock prefix is implicit for xchg.
++                       : "=r"(new_value)
++                       : "m"(*ptr), "0"(new_value)
++                       : "memory");
++  return new_value;  // Now it's the previous value.
++}
++
++inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
++                                          Atomic32 increment) {
++  Atomic32 temp = increment;
++  __asm__ __volatile__("lock; xaddl %0,%1"
++                       : "+r"(temp), "+m"(*ptr)
++                       :
++                       : "memory");
++  // temp now holds the old value of *ptr
++  return temp + increment;
++}
++
++inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
++                                        Atomic32 increment) {
++  Atomic32 temp = increment;
++  __asm__ __volatile__("lock; xaddl %0,%1"
++                       : "+r"(temp), "+m"(*ptr)
++                       :
++                       : "memory");
++  // temp now holds the old value of *ptr
++  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
++    __asm__ __volatile__("lfence" : : : "memory");
++  }
++  return temp + increment;
++}
++
++inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
++                                       Atomic32 old_value,
++                                       Atomic32 new_value) {
++  Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
++  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
++    __asm__ __volatile__("lfence" : : : "memory");
++  }
++  return x;
++}
++
++inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
++                                       Atomic32 old_value,
++                                       Atomic32 new_value) {
++  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
++}
++
++inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
++  *ptr = value;
++}
++
++inline void MemoryBarrier() {
++  __asm__ __volatile__("mfence" : : : "memory");
++}
++
++inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
++  *ptr = value;
++  MemoryBarrier();
++}
++
++inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
++  ATOMICOPS_COMPILER_BARRIER();
++  *ptr = value;  // An x86 store acts as a release barrier.
++  // See comments in Atomic64 version of Release_Store(), below.
++}
++
++inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
++  return *ptr;
++}
++
++inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
++  Atomic32 value = *ptr;  // An x86 load acts as a acquire barrier.
++  // See comments in Atomic64 version of Release_Store(), below.
++  ATOMICOPS_COMPILER_BARRIER();
++  return value;
++}
++
++inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
++  MemoryBarrier();
++  return *ptr;
++}
++
++#if defined(__x86_64__)
++
++// 64-bit low-level operations on 64-bit platform.
++
++inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
++                                         Atomic64 old_value,
++                                         Atomic64 new_value) {
++  Atomic64 prev;
++  __asm__ __volatile__("lock; cmpxchgq %1,%2"
++                       : "=a"(prev)
++                       : "q"(new_value), "m"(*ptr), "0"(old_value)
++                       : "memory");
++  return prev;
++}
++
++inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
++                                         Atomic64 new_value) {
++  __asm__ __volatile__("xchgq %1,%0"  // The lock prefix is implicit for xchg.
++                       : "=r"(new_value)
++                       : "m"(*ptr), "0"(new_value)
++                       : "memory");
++  return new_value;  // Now it's the previous value.
++}
++
++inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
++                                          Atomic64 increment) {
++  Atomic64 temp = increment;
++  __asm__ __volatile__("lock; xaddq %0,%1"
++                       : "+r"(temp), "+m"(*ptr)
++                       :
++                       : "memory");
++  // temp now contains the previous value of *ptr
++  return temp + increment;
++}
++
++inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
++                                        Atomic64 increment) {
++  Atomic64 temp = increment;
++  __asm__ __volatile__("lock; xaddq %0,%1"
++                       : "+r"(temp), "+m"(*ptr)
++                       :
++                       : "memory");
++  // temp now contains the previous value of *ptr
++  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
++    __asm__ __volatile__("lfence" : : : "memory");
++  }
++  return temp + increment;
++}
++
++inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
++  *ptr = value;
++}
++
++inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
++  *ptr = value;
++  MemoryBarrier();
++}
++
++inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
++  ATOMICOPS_COMPILER_BARRIER();
++
++  *ptr = value;  // An x86 store acts as a release barrier
++                 // for current AMD/Intel chips as of Jan 2008.
++                 // See also Acquire_Load(), below.
++
++  // When new chips come out, check:
++  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
++  //  System Programming Guide, Chatper 7: Multiple-processor management,
++  //  Section 7.2, Memory Ordering.
++  // Last seen at:
++  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
++  //
++  // x86 stores/loads fail to act as barriers for a few instructions (clflush
++  // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
++  // not generated by the compiler, and are rare.  Users of these instructions
++  // need to know about cache behaviour in any case since all of these involve
++  // either flushing cache lines or non-temporal cache hints.
++}
++
++inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
++  return *ptr;
++}
++
++inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
++  Atomic64 value = *ptr;  // An x86 load acts as a acquire barrier,
++                          // for current AMD/Intel chips as of Jan 2008.
++                          // See also Release_Store(), above.
++  ATOMICOPS_COMPILER_BARRIER();
++  return value;
++}
++
++inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
++  MemoryBarrier();
++  return *ptr;
++}
++
++inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
++                                       Atomic64 old_value,
++                                       Atomic64 new_value) {
++  Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
++  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
++    __asm__ __volatile__("lfence" : : : "memory");
++  }
++  return x;
++}
++
++inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
++                                       Atomic64 old_value,
++                                       Atomic64 new_value) {
++  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
++}
++
++#endif  // defined(__x86_64__)
++
++}  // namespace base::subtle
++}  // namespace base
++
++#undef ATOMICOPS_COMPILER_BARRIER
++
++#endif  // CEF_INCLUDE_BASE_INTERNAL_CEF_ATOMICOPS_X86_GCC_H_
+--- cef_binary_3.3359.1774.gd49d25f_windows32/cmake/cef_variables.cmake.orig	2019-04-02 19:37:47.332457010 +0200
++++ cef_binary_3.3359.1774.gd49d25f_windows32/cmake/cef_variables.cmake	2019-03-09 14:17:10.333854000 +0100
+@@ -70,6 +70,8 @@
+ # Linux configuration.
+ #
+ 
++set(OS_LINUX true)
++set(OS_WINDOWS false)
+ if(OS_LINUX)
+   # Platform-specific compiler/linker flags.
+   set(CEF_LIBTYPE SHARED)
+@@ -185,21 +187,24 @@
+     )
+ 
+   # CEF directory paths.
++  # CEF directory paths.
+   set(CEF_RESOURCE_DIR        "${_CEF_ROOT}/Resources")
+-  set(CEF_BINARY_DIR          "${_CEF_ROOT}/${CMAKE_BUILD_TYPE}")
++  set(CEF_BINARY_DIR          "${_CEF_ROOT}/$<CONFIGURATION>")
+   set(CEF_BINARY_DIR_DEBUG    "${_CEF_ROOT}/Debug")
+   set(CEF_BINARY_DIR_RELEASE  "${_CEF_ROOT}/Release")
+ 
+   # CEF library paths.
+-  set(CEF_LIB_DEBUG   "${CEF_BINARY_DIR_DEBUG}/libcef.so")
+-  set(CEF_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/libcef.so")
++  set(CEF_LIB_DEBUG   "${CEF_BINARY_DIR_DEBUG}/libcef.lib")
++  set(CEF_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/libcef.lib")
+ 
+   # List of CEF binary files.
+   set(CEF_BINARY_FILES
+-    chrome-sandbox
+-    libcef.so
+-    libEGL.so
+-    libGLESv2.so
++    chrome_elf.dll
++    d3dcompiler_43.dll
++    d3dcompiler_47.dll
++    libcef.dll
++    libEGL.dll
++    libGLESv2.dll
+     natives_blob.bin
+     snapshot_blob.bin
+     v8_context_snapshot.bin
+@@ -216,6 +221,25 @@
+     icudtl.dat
+     locales
+     )
++
++  if(USE_SANDBOX)
++    list(APPEND CEF_COMPILER_DEFINES
++      PSAPI_VERSION=1   # Required by cef_sandbox.lib
++      CEF_USE_SANDBOX   # Used by apps to test if the sandbox is enabled
++      )
++
++    # Libraries required by cef_sandbox.lib.
++    set(CEF_SANDBOX_STANDARD_LIBS
++      dbghelp.lib
++      psapi.lib
++      version.lib
++      winmm.lib
++      )
++
++    # CEF sandbox library paths.
++    set(CEF_SANDBOX_LIB_DEBUG "${CEF_BINARY_DIR_DEBUG}/cef_sandbox.lib")
++    set(CEF_SANDBOX_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/cef_sandbox.lib")
++  endif()
+ endif()
+ 
+ 
Index: docker/msys/cefpython-66.0.patch
===================================================================
--- docker/msys/cefpython-66.0.patch	(revision 936)
+++ docker/msys/cefpython-66.0.patch	(revision 936)
@@ -0,0 +1,224 @@
+--- cefpython-66.0/tools/build_cpp_projects.py.orig	2019-04-02 16:58:20.961263518 +0200
++++ cefpython-66.0/tools/build_cpp_projects.py	2019-03-09 16:32:28.031876000 +0100
+@@ -1,4 +1,4 @@
+-# Copyright (c) 2017 CEF Python, see the Authors file.
++# Copyright (c) 2017 CEF Python, see the Authors file
+ # All rights reserved. Licensed under BSD 3-clause license.
+ # Project website: https://github.com/cztomczak/cefpython
+ 
+@@ -46,16 +46,19 @@
+ 
+ # Compiler args
+ COMPILER_ARGS = [
+-    "/EHsc",
++    #"/EHsc",
+ ]
+ subprocess_COMPILER_ARGS = [
+-    "/MT",
++    #"/MT",
++    "-pthread",
+ ]
+ 
+ # Linker args
+ subprocess_LINKER_ARGS = [
+-    "/MANIFEST:NO",
+-    "/LARGEADDRESSAWARE",
++    #"/MANIFEST:NO",
++    #"/LARGEADDRESSAWARE",
++    "-fstack-protector-all",
++    "-Wl,--subsystem,windows"
+ ]
+ 
+ # Command line args
+@@ -110,11 +112,11 @@
+ def get_compiler(static=False):
+     # NOTES:
+     # - VS2008 and VS2010 are both using distutils/msvc9compiler.py
+-    compiler = new_compiler()
++    compiler = new_compiler(verbose = True)
+     # Must initialize so that "compile_options" and others are available
+-    compiler.initialize()
++    #compiler.initialize()
+     if static:
+-        compiler.compile_options.remove("/MD")
++        #compiler.compile_options.remove("/MD")
+         # Overwrite function that adds /MANIFESTFILE, as for subprocess
+         # manifest is disabled. Otherwise warning LNK4075 is generated.
+         if hasattr(compiler, "manifest_setup_ldargs"):
+@@ -179,11 +181,13 @@
+                                  output_progname="subprocess",
+                                  output_dir=BUILD_SUBPROCESS,
+                                  libraries=["libcef",
+-                                            "libcef_dll_wrapper_MT"],
++                                            "cef_dll_wrapper",
++                                            "libcef"],
+                                  library_dirs=[lib_dir, lib_dir_vs],
+                                  # TODO linker flags for Linux/Mac
+                                  extra_preargs=None,
+-                                 extra_postargs=subprocess_LINKER_ARGS)
++                                 extra_postargs=subprocess_LINKER_ARGS,
++                                 target_lang="c++")
+     else:
+         print("[build_cpp_projects.py] Executable is up-to-date: subprocess")
+ 
+--- cefpython-66.0/tools/cython_setup.py.orig	2019-04-02 16:58:31.753618071 +0200
++++ cefpython-66.0/tools/cython_setup.py	2019-03-09 16:53:19.516724000 +0100
+@@ -129,6 +129,7 @@
+                 r"C:\\Program Files\\Microsoft SDKs\\Windows\\v7.0\\Lib",
+                 # Visual Studio 2008 installation
+                 r"C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0A\\Lib",
++                r"C:\\msys64\\mingw32\\lib"
+             ]
+         elif ARCH64:
+             winsdk_libs = [
+@@ -180,8 +181,37 @@
+         #
+         # The above warning LNK4217 is caused by the warning below which occurs
+         # when building the client_handler.lib static library:
+-        extra_compile_args.extend(["/EHsc", "/wd4305"])
+-        extra_link_args.extend(["/ignore:4217"])
++        #extra_compile_args.extend(["/EHsc", "/wd4305"])
++        #extra_link_args.extend(["/ignore:4217"])
++        if FAST_FLAG:
++            extra_compile_args.append("-O0")
++        else:
++            extra_compile_args.append("-O3")
++
++        extra_compile_args.extend([
++                "-DNDEBUG",
++                "-std=gnu++11",
++        ])
++        os.environ["CC"] = "g++"
++        os.environ["CXX"] = "g++"
++        extra_compile_args.extend(["-std=gnu++11"])
++
++        # Fix "ImportError ... undefined symbol ..." caused by CEF's
++        # include/base/ headers by adding the -flto flag (Issue #230).
++        # Unfortunately -flto prolongs compilation time significantly.
++        # More on the other flags: https://stackoverflow.com/questions/
++        # 6687630/ .
++
++        if FAST_FLAG:
++            extra_compile_args.extend(["-flto"])
++            extra_link_args.extend(["-flto"])
++        else:
++            extra_compile_args.extend(["-flto",
++                                       "-fdata-sections",
++                                       "-ffunction-sections"])
++            extra_link_args.extend(["-flto",
++                                    "-Wl,--gc-sections"])
++        extra_link_args.extend(["-fstack-protector-all"])
+ 
+     if LINUX or MAC:
+         # Compiler flags
+@@ -365,12 +395,13 @@
+     libraries = list()
+     if WINDOWS:
+         libraries.extend([
++            "cef_dll_wrapper",
+             "libcef",
+-            "libcef_dll_wrapper_MD",
+             "User32",
+             "cefpython_app",
+             "cpp_utils",
+             "client_handler",
++            "gdi32"
+         ])
+     elif MAC:
+         libraries.extend([
+--- cefpython-66.0/src/subprocess/main.cpp.orig	2019-04-02 20:36:34.016395754 +0200
++++ cefpython-66.0/src/subprocess/main.cpp	2019-04-02 20:39:33.491183098 +0200
+@@ -7,10 +7,10 @@
+ #if defined(OS_WIN)
+ 
+ #include <windows.h>
+-int APIENTRY wWinMain(HINSTANCE hInstance,
+-                      HINSTANCE hPrevInstance,
+-                      LPTSTR    lpCmdLine,
+-                      int       nCmdShow)
++int APIENTRY WinMain(HINSTANCE hInstance,
++                     HINSTANCE hPrevInstance,
++                     LPSTR     lpCmdLine,
++                     int       nCmdShow)
+ {
+ 	UNREFERENCED_PARAMETER(hPrevInstance);
+ 	UNREFERENCED_PARAMETER(lpCmdLine);
+--- cefpython-66.0/tools/make_installer.py.orig	2018-08-20 19:51:17.000000000 +0200
++++ cefpython-66.0/tools/make_installer.py	2019-04-02 20:59:22.372933492 +0200
+@@ -102,7 +102,7 @@
+     create_empty_log_file(os.path.join(PKG_DIR, "debug.log"))
+     create_empty_log_file(os.path.join(PKG_DIR, "examples/debug.log"))
+ 
+-    copy_cpp_extension_dependencies_issue359(PKG_DIR)
++    #copy_cpp_extension_dependencies_issue359(PKG_DIR)
+ 
+     print("[make_installer.py] Done. Installer package created: {setup_dir}"
+           .format(setup_dir=SETUP_DIR))
+--- cefpython-66.0/tools/build.py.orig	2019-04-02 16:58:17.137138263 +0200
++++ cefpython-66.0/tools/build.py	2019-04-12 21:32:28.414197037 +0200
+@@ -79,6 +79,7 @@
+ # Command line args variables
+ SYS_ARGV_ORIGINAL = None
+ VERSION = ""
++NO_RUN_TESTS = False
+ NO_RUN_EXAMPLES = False
+ DEBUG_FLAG = False
+ FAST_FLAG = False
+@@ -125,7 +126,7 @@
+ 
+ def command_line_args():
+     global DEBUG_FLAG, FAST_FLAG, CLEAN_FLAG, KIVY_FLAG, HELLO_WORLD_FLAG, \
+-           REBUILD_CPP, VERSION, NO_RUN_EXAMPLES
++           REBUILD_CPP, VERSION, NO_RUN_TESTS, NO_RUN_EXAMPLES
+ 
+     VERSION = get_version_from_command_line_args(__file__)
+     # Other scripts called by this script expect that version number
+@@ -140,6 +141,11 @@
+     global SYS_ARGV_ORIGINAL
+     SYS_ARGV_ORIGINAL = copy.copy(sys.argv)
+ 
++    if "--no-run-tests" in sys.argv:
++        NO_RUN_TESTS = True
++        print("[build.py] Running tests disabled (--no-run-tests)")
++        sys.argv.remove("--no-run-tests")
++
+     if "--no-run-examples" in sys.argv:
+         NO_RUN_EXAMPLES = True
+         print("[build.py] Running examples disabled (--no-run-examples)")
+@@ -820,8 +826,8 @@
+         sys.exit(1)
+ 
+     # Move the cefpython module
+-    module_pattern = MODULE_NAME_TEMPLATE.format(pyversion=PYVERSION+"*",
+-                                                 ext=MODULE_EXT)
++    module_pattern = "cefpython_py{pyversion}-cpython-{pyversion}m.dll".\
++                     format(pyversion=PYVERSION+"*", ext=MODULE_EXT)
+     module_pattern = "./build/lib*/" + module_pattern
+     move_file_by_pattern(module_pattern, os.path.join(CEFPYTHON_BINARY,
+                                                       MODULE_NAME))
+@@ -902,15 +908,16 @@
+     delete_directory_reliably(setup_installer_dir)
+ 
+     # Run unittests
+-    print("[build.py] Run unittests")
+-    test_runner = os.path.join(UNITTESTS_DIR, "_test_runner.py")
+-    command = ("\"{python}\" {test_runner}"
+-               .format(python=sys.executable,
+-                       test_runner=test_runner))
+-    ret = os.system(command)
+-    if ret != 0:
+-        print("[build.py] ERROR while running unit tests")
+-        sys.exit(1)
++    if not NO_RUN_TESTS:
++        print("[build.py] Run unittests")
++        test_runner = os.path.join(UNITTESTS_DIR, "_test_runner.py")
++        command = ("\"{python}\" {test_runner}"
++                   .format(python=sys.executable,
++                           test_runner=test_runner))
++        ret = os.system(command)
++        if ret != 0:
++            print("[build.py] ERROR while running unit tests")
++            sys.exit(1)
+ 
+     # Run examples
+     if not NO_RUN_EXAMPLES:
Index: docker/msys/py2exe.patch
===================================================================
--- docker/msys/py2exe.patch	(revision 936)
+++ docker/msys/py2exe.patch	(revision 936)
@@ -0,0 +1,736 @@
+diff --git a/py2exe/distutils_buildexe.py b/py2exe/distutils_buildexe.py
+index ae8aca3..d809641 100644
+--- a/py2exe/distutils_buildexe.py
++++ b/py2exe/distutils_buildexe.py
+@@ -154,6 +154,7 @@ class py2exe(Command):
+         self.ascii = 0
+         self.custom_boot_script = None
+         self.use_assembly = False
++        self.gi_namespaces = []
+ 
+     def finalize_options (self):
+         self.optimize = int(self.optimize)
+@@ -239,6 +240,7 @@ class py2exe(Command):
+                             excludes = self.excludes,
+                             ignores = self.ignores,
+                             packages = self.packages,
++                            gi_namespaces = self.gi_namespaces,
+                             dist_dist = self.dist_dir,
+                             dll_excludes = self.dll_excludes,
+                             typelibs = self.typelibs,
+diff --git a/py2exe/dllfinder.py b/py2exe/dllfinder.py
+index 4e5e76c..bb43f9e 100644
+--- a/py2exe/dllfinder.py
++++ b/py2exe/dllfinder.py
+@@ -68,7 +68,8 @@ class DllFinder:
+             if dll in self._loaded_dlls:
+                 continue
+             for dep_dll in self.bind_image(dll):
+-                if dep_dll in self._loaded_dlls:
++                bname = os.path.basename(dep_dll).lower()
++                if bname in self._loaded_dlls:
+                     continue
+                 dll_type = self.determine_dll_type(dep_dll)
+                 if dll_type is None:
+@@ -144,7 +145,8 @@ class DllFinder:
+         deps = self.bind_image(imagename)
+         if pydll in [d.lower() for d in deps]:
+             return "EXT"
+-        if fnm.startswith(windir + os.sep) or fnm.startswith(sysdir + os.sep):
++        if fnm.startswith(windir + os.sep) or fnm.startswith(sysdir + os.sep) or \
++           fnm.startswith(windir + '\\') or fnm.startswith(sysdir + '\\'):
+             return None
+         return "DLL"
+ 
+diff --git a/py2exe/gihelper.py b/py2exe/gihelper.py
+index e69de29..f597692 100644
+--- a/py2exe/gihelper.py
++++ b/py2exe/gihelper.py
+@@ -0,0 +1,58 @@
++
++import cffi
++
++class GIHelper(object):
++    _cdef="""
++        typedef char gchar;
++        typedef int gint;
++        typedef uint32_t guint32;
++        typedef guint32 GQuark;
++
++        typedef struct {
++          GQuark    domain;
++          gint      code;
++          gchar     *message;
++        } GError;
++
++        typedef struct _GITypelib GITypelib;
++        typedef struct _GIRepository         GIRepository;
++
++        typedef enum
++        {
++          G_IREPOSITORY_LOAD_FLAG_LAZY = 1
++        } GIRepositoryLoadFlags;
++
++        GIRepository *g_irepository_get_default   (void);
++
++        GITypelib *    g_irepository_require       (GIRepository *repository,
++                               const gchar  *namespace_,
++                               const gchar  *version,
++                               GIRepositoryLoadFlags flags,
++                               GError      **error);
++
++        const gchar * g_irepository_get_shared_library (GIRepository *repository,
++                                const gchar  *namespace_);
++        """
++
++    def __init__(self):
++        self._ffi = cffi.FFI()
++        self._ffi.cdef(self._cdef)
++
++        self._lib = self._ffi.dlopen("libgirepository-1.0-1.dll")
++
++        self._repo=self._lib.g_irepository_get_default()
++
++        self._error = self._ffi.new("GError**")
++
++    def getSharedLibraries(self, namespace, version):
++        typelib = self._lib.g_irepository_require(self._repo,
++                                        bytes(namespace, "utf-8"),
++                                        bytes(version, "utf-8"),
++                                        0, self._error)
++        if typelib == self._ffi.NULL:
++            return []
++        else:
++            return str(
++                self._ffi.string(
++                    self._lib.g_irepository_get_shared_library(
++                        self._repo, bytes(namespace, "utf-8"))), "utf-8").split(",")
+diff --git a/py2exe/mf3.py b/py2exe/mf3.py
+index f645740..ec1f261 100644
+--- a/py2exe/mf3.py
++++ b/py2exe/mf3.py
+@@ -5,6 +5,7 @@
+ 
+ # XXX XXX XXX Does not yet support PEP 452 namespace packages!
+ 
++from . import gihelper
+ from collections import defaultdict
+ import dis
+ import importlib
+@@ -21,6 +22,9 @@ LOAD_CONST = dis.opname.index('LOAD_CONST')
+ IMPORT_NAME = dis.opname.index('IMPORT_NAME')
+ STORE_NAME = dis.opname.index('STORE_NAME')
+ STORE_GLOBAL = dis.opname.index('STORE_GLOBAL')
++LOAD_NAME = dis.opname.index('LOAD_NAME')
++LOAD_METHOD = dis.opname.index('LOAD_METHOD')
++CALL_METHOD = dis.opname.index('CALL_METHOD')
+ STORE_OPS = [STORE_NAME, STORE_GLOBAL]
+ HAVE_ARGUMENT = dis.HAVE_ARGUMENT
+ 
+@@ -63,7 +67,7 @@ class ModuleFinder:
+         self._depgraph = defaultdict(set)
+         self._indent = ""
+         self._package_paths = defaultdict(list)
+-
++        self._gihelper = gihelper.GIHelper()
+ 
+     def add_packagepath(self, packagename, path):
+         """ModuleFinder can not handle __path__ modifications packages
+@@ -416,7 +420,6 @@ class ModuleFinder:
+         We also take note of 'static' global symbols in the module and
+         add them to __globalnames__.
+         """
+-
+         for what, args in self._scan_opcodes(code):
+             if what == "store":
+                 name, = args
+@@ -424,6 +427,11 @@ class ModuleFinder:
+             elif what == "import":
+                 level, fromlist, name = args
+                 self.safe_import_hook(name, mod, fromlist, level)
++            elif what == "gi_request":
++                for sharedLibrary in \
++                    self._gihelper.getSharedLibraries(args[0], args[1]):
++                    from . dllfinder import SearchPath
++                    self.add_dll(SearchPath(sharedLibrary))
+             else:
+                 # We don't expect anything else from the generator.
+                 raise RuntimeError(what)
+@@ -442,10 +450,15 @@ class ModuleFinder:
+             # dis.get_instructions() is only available in python 3.4
+             # and higher
+             instructions = []
++
++            requireCallLevel = 0
++            requiredNamespace = None
++            requiredVersion = None
+             for inst in dis.get_instructions(co):
+                 instructions.append(inst)
+                 c = inst.opcode
+                 if c == IMPORT_NAME:
++                    requireCallLevel = 0
+                     assert instructions[-3].opcode == LOAD_CONST
+                     level = instructions[-3].argval
+                     assert instructions[-2].opcode == LOAD_CONST
+@@ -453,7 +466,34 @@ class ModuleFinder:
+                     name = inst.argval
+                     yield "import", (level, fromlist, name)
+                 elif c in STORE_OPS:
++                    requireCallLevel = 0
+                     yield "store", (inst.argval,)
++                elif c == LOAD_NAME:
++                    if requireCallLevel==0 and inst.argval=="gi":
++                        requireCallLevel += 1
++                    else:
++                        requireCallLevel = 0
++                elif c == LOAD_METHOD:
++                    if requireCallLevel==1 and inst.argval=="require_version":
++                        requireCallLevel += 1
++                    else:
++                        requireCallLevel = 0
++                elif c==LOAD_CONST:
++                    if requireCallLevel==2:
++                        requiredNamespace = inst.argval
++                        requireCallLevel += 1
++                    elif requireCallLevel==3:
++                        requiredVersion = inst.argval
++                        requireCallLevel += 1
++                    else:
++                        requireCallLevel = 0
++                elif c==CALL_METHOD:
++                    if requireCallLevel==4:
++                        yield ("gi_request", (requiredNamespace, requiredVersion))
++                    requireCallLevel = 0
++                    requiredNamespace = None
++                    requiredVersion = None
++
+         else:
+             code = co.co_code
+             names = co.co_names
+diff --git a/py2exe/py2exe_distutils.py b/py2exe/py2exe_distutils.py
+index 3918849..fe97b90 100644
+--- a/py2exe/py2exe_distutils.py
++++ b/py2exe/py2exe_distutils.py
+@@ -1,5 +1,5 @@
+ # This file is only used when BUILDING py2exe.
+-import os, sys
++import os, sys, types, copy
+ 
+ from distutils.core import Extension
+ from distutils.dist import Distribution
+@@ -8,12 +8,17 @@ from distutils.sysconfig import customize_compiler
+ from distutils.dep_util import newer_group
+ from distutils.errors import DistutilsError, DistutilsSetupError, DistutilsPlatformError
+ from distutils.errors import CCompilerError, CompileError
++from distutils.file_util import write_file
+ from distutils.util import get_platform
+ from distutils import log
+ 
+-# We don't need a manifest in the executable, so monkeypatch the code away:
+-from distutils.msvc9compiler import MSVCCompiler
+-MSVCCompiler.manifest_setup_ldargs = lambda *args: None
++from distutils import ccompiler
++isMingw32 = ccompiler.get_default_compiler()=='mingw32'
++
++if not isMingw32:
++    # We don't need a manifest in the executable, so monkeypatch the code away:
++    from distutils.msvc9compiler import MSVCCompiler
++    MSVCCompiler.manifest_setup_ldargs = lambda *args: None
+ 
+ class Interpreter(Extension):
+     def __init__(self, *args, **kw):
+@@ -38,6 +43,82 @@ class Dist(Distribution):
+     def has_extensions(self):
+         return False
+ 
++def mingw32_link(self, target_desc, objects, output_filename, output_dir=None,
++             libraries=None, library_dirs=None, runtime_library_dirs=None,
++             export_symbols=None, debug=0, extra_preargs=None,
++             extra_postargs=None, build_temp=None, target_lang=None):
++    """Link the objects."""
++    from distutils.unixccompiler import UnixCCompiler
++
++    # use separate copies, so we can modify the lists
++    extra_preargs = copy.copy(extra_preargs or [])
++    libraries = copy.copy(libraries or [])
++    objects = copy.copy(objects or [])
++
++    # Additional libraries
++    libraries.extend(self.dll_libraries)
++
++    # handle export symbols by creating a def-file
++    # with executables this only works with gcc/ld as linker
++    if ((export_symbols is not None) and
++        (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
++        # (The linker doesn't do anything if output is up-to-date.
++        # So it would probably better to check if we really need this,
++        # but for this we had to insert some unchanged parts of
++        # UnixCCompiler, and this is not what we want.)
++
++        # we want to put some files in the same directory as the
++        # object files are, build_temp doesn't help much
++        # where are the object files
++        temp_dir = os.path.dirname(objects[0])
++        # name of dll to give the helper files the same base name
++        (dll_name, dll_extension) = os.path.splitext(
++            os.path.basename(output_filename))
++
++        # generate the filenames for these files
++        def_file = os.path.join(temp_dir, dll_name + ".def")
++        lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a")
++
++        # Generate .def file
++        contents = ["EXPORTS"]
++        for sym in export_symbols:
++            contents.append(sym)
++        self.execute(write_file, (def_file, contents),
++                     "writing %s" % def_file)
++
++        # next add options for def-file and to creating import libraries
++
++        # dllwrap uses different options than gcc/ld
++        if self.linker_dll == "dllwrap":
++            extra_preargs.extend(["--output-lib", lib_file])
++            # for dllwrap we have to use a special option
++            extra_preargs.extend(["--def", def_file])
++            # we use gcc/ld here and can be sure ld is >= 2.9.10
++        else:
++            # doesn't work: bfd_close build\...\libfoo.a: Invalid operation
++            #extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file])
++            # for gcc/ld the def-file is specified as any object files
++            objects.append(def_file)
++
++    #end: if ((export_symbols is not None) and
++    #        (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
++
++    # who wants symbols and a many times larger output file
++    # should explicitly switch the debug mode on
++    # otherwise we let dllwrap/ld strip the output file
++    # (On my machine: 10KiB < stripped_file < ??100KiB
++    #   unstripped_file = stripped_file + XXX KiB
++    #  ( XXX=254 for a typical python extension))
++    if not debug and not hasattr(sys, 'gettotalrefcount'):
++        extra_preargs.append("-s")
++
++    UnixCCompiler.link(self, target_desc, objects, output_filename,
++                       output_dir, libraries, library_dirs,
++                       runtime_library_dirs,
++                       None, # export_symbols, we do this in our def-file
++                       debug, extra_preargs, extra_postargs, build_temp,
++                       target_lang)
++
+ class BuildInterpreters(build_ext.build_ext):
+     description = "build special python interpreter stubs"
+ 
+@@ -67,6 +148,9 @@ class BuildInterpreters(build_ext.build_ext):
+         if os.name == 'nt' and self.plat_name != get_platform():
+             self.compiler.initialize(self.plat_name)
+ 
++        if isMingw32:
++            self.compiler.link = types.MethodType(mingw32_link, self.compiler)
++
+         # And make sure that any compile/link-related options (which might
+         # come from the command-line or from the setup script) are set in
+         # that CCompiler object -- that way, they automatically apply to
+@@ -190,7 +274,7 @@ class BuildInterpreters(build_ext.build_ext):
+                            libraries=self.get_libraries(ext),
+                            library_dirs=ext.library_dirs,
+                            runtime_library_dirs=ext.runtime_library_dirs,
+-                           export_symbols=ext.export_symbols,
++                           export_symbols=ext.export_symbols if ext.export_symbols else None,
+                            extra_postargs=extra_args,
+                            debug=self.debug)
+ 
+diff --git a/py2exe/runtime.py b/py2exe/runtime.py
+index 10b0fa9..d154ff7 100644
+--- a/py2exe/runtime.py
++++ b/py2exe/runtime.py
+@@ -19,8 +19,8 @@ from .icons import BuildIcons
+ 
+ logger = logging.getLogger("runtime")
+ 
+-#from importlib.machinery import EXTENSION_SUFFIXES
+-EXTENSION_SUFFIXES = ['.pyd']
++from importlib.machinery import EXTENSION_SUFFIXES
++#EXTENSION_SUFFIXES = ['.pyd']
+ from importlib.machinery import DEBUG_BYTECODE_SUFFIXES, OPTIMIZED_BYTECODE_SUFFIXES
+ 
+ RT_MANIFEST = 24
+@@ -248,12 +248,15 @@ class Runtime(object):
+             if os.path.isfile(libpath):
+                 os.remove(libpath)
+ 
+-            if not os.path.exists(os.path.dirname(libpath)):
+-                os.mkdir(os.path.dirname(libpath))
+-
+-            dll_bytes = pkgutil.get_data("py2exe", "resources.dll")
+-            with open(libpath, "wb") as ofi:
+-                  ofi.write(dll_bytes)
++            if self.options.skip_archive:
++                if not os.path.exists(libpath):
++                    os.makedirs(libpath)
++            else:
++                if not os.path.exists(os.path.dirname(libpath)):
++                    os.mkdir(os.path.dirname(libpath))
++                dll_bytes = pkgutil.get_data("py2exe", "resources.dll")
++                with open(libpath, "wb") as ofi:
++                    ofi.write(dll_bytes)
+             if options.verbose:
+                 print("Building shared code archive '%s'." % libpath)
+             # Archive is appended to resources.dll; remove the icon
+@@ -263,7 +266,7 @@ class Runtime(object):
+ 
+         self.copy_files(destdir)
+ 
+-        # data directories from modulefinder
++        # data directories from modulefinder
+         for name, (src, recursive) in self.mf._data_directories.items():
+             if recursive:
+                 dst = os.path.join(destdir, name)
+@@ -274,11 +277,11 @@ class Runtime(object):
+             else:
+                 raise RuntimeError("not yet supported")
+ 
+-        # data files from modulefinder
+-        for name, src in self.mf._data_files.items():
+-            dst = os.path.join(destdir, name)
+-            shutil.copy2(src, dst)
+-
++        # data files from modulefinder
++        for name, src in self.mf._data_files.items():
++            dst = os.path.join(destdir, name)
++            shutil.copy2(src, dst)
++
+         # other data files
+         if self.options.data_files:
+             for subdir, files in self.options.data_files:
+@@ -410,46 +413,38 @@ class Runtime(object):
+             compression = zipfile.ZIP_STORED
+ 
+         # Create a zipfile and append it to the library file
+-        arc = zipfile.ZipFile(libpath, "a",
+-                              compression=compression)
+-
+-        # The same modules may be in self.ms.modules under different
+-        # keys; we only need one of them in the archive.
+-        for mod in set(self.mf.modules.values()):
+-            if mod.__code__:
+-                if hasattr(mod, "__path__"):
+-                    path = mod.__name__.replace(".", "\\") + "\\__init__" + bytecode_suffix
+-                else:
+-                    path = mod.__name__.replace(".", "\\") + bytecode_suffix
+-                stream = io.BytesIO()
+-                stream.write(imp.get_magic())
+-                if sys.version_info >= (3,7,0):
+-                    stream.write(b"\0\0\0\0") # null flags
+-                stream.write(b"\0\0\0\0") # null timestamp
+-                stream.write(b"\0\0\0\0") # null size
+-                marshal.dump(mod.__code__, stream)
+-                arc.writestr(path, stream.getvalue())
+-
+-            elif hasattr(mod, "__file__"):
+-                #assert mod.__file__.endswith(EXTENSION_SUFFIXES[0])
+-                if self.options.bundle_files <= 2:
+-                    # put .pyds into the archive
+-                    arcfnm = mod.__name__.replace(".", "\\") + EXTENSION_SUFFIXES[0]
+-                    if self.options.verbose > 1:
+-                        print("Add %s to %s" % (os.path.basename(mod.__file__), libpath))
+-                    arc.write(mod.__file__, arcfnm)
+-                else:
+-                    # The extension modules will be copied into
+-                    # dlldir.  To be able to import it without dlldir
+-                    # being on sys.path, create a loader module and
+-                    # put that into the archive.
+-                    pydfile = mod.__name__ + EXTENSION_SUFFIXES[0]
+-                    if self.options.verbose > 1:
+-                        print("Add Loader for %s to %s" % (os.path.basename(mod.__file__), libpath))
+-                    loader = LOAD_FROM_DIR.format(pydfile)
+-
+-                    code = compile(loader, "<loader>", "exec",
+-                                   optimize=self.options.optimize)
++        if self.options.skip_archive:
++            for mod in set(self.mf.modules.values()):
++                if hasattr(mod, "__file__"):
++                    path = os.path.join(*mod.__name__.split("."))
++                    if hasattr(mod, "__path__"):
++                        path = os.path.join(path, "__init__")
++                    path += bytecode_suffix if mod.__code__ else EXTENSION_SUFFIXES[0]
++                    path = os.path.join(libpath, path)
++                    dirpath = os.path.dirname(path)
++                    if not os.path.isdir(dirpath):
++                        os.makedirs(dirpath)
++                    if mod.__code__:
++                        with open(mod.__file__, "rt") as fin:
++                            code = compile(fin.read(), mod.__file__, "exec",
++                                           optimize=self.options.optimize)
++                        with open(path, "wb") as fout:
++                            fout.write(imp.get_magic())
++                            if sys.version_info >= (3,7,0):
++                                fout.write(b"\0\0\0\0") # null flags
++                            fout.write(b"\0\0\0\0") # null timestamp
++                            fout.write(b"\0\0\0\0") # null size
++                            marshal.dump(code, fout)
++                    else:
++                        shutil.copy2(mod.__file__, path)
++        else:
++            arc = zipfile.ZipFile(libpath, "a",
++                                  compression=compression)
++
++            # The same modules may be in self.ms.modules under different
++            # keys; we only need one of them in the archive.
++            for mod in set(self.mf.modules.values()):
++                if mod.__code__:
+                     if hasattr(mod, "__path__"):
+                         path = mod.__name__.replace(".", "\\") + "\\__init__" + bytecode_suffix
+                     else:
+@@ -457,28 +452,61 @@ class Runtime(object):
+                     stream = io.BytesIO()
+                     stream.write(imp.get_magic())
+                     if sys.version_info >= (3,7,0):
+-                        stream.write(b"\0\0\0\0") # null flags
++                        stream.write(b"\0\0\0\0") # null flags
+                     stream.write(b"\0\0\0\0") # null timestamp
+                     stream.write(b"\0\0\0\0") # null size
+-                    marshal.dump(code, stream)
++                    marshal.dump(mod.__code__, stream)
+                     arc.writestr(path, stream.getvalue())
+ 
+-        if self.options.bundle_files == 0:
+-            # put everything into the arc
+-            files = self.mf.all_dlls()
+-        elif self.options.bundle_files in (1, 2):
+-            # put only extension dlls into the arc
+-            files = self.mf.extension_dlls()
+-        else:
+-            arc.close()
+-            return
++                elif hasattr(mod, "__file__"):
++                    #assert mod.__file__.endswith(EXTENSION_SUFFIXES[0])
++                    if self.options.bundle_files <= 2:
++                        # put .pyds into the archive
++                        arcfnm = mod.__name__.replace(".", "\\") + EXTENSION_SUFFIXES[0]
++                        if self.options.verbose > 1:
++                            print("Add %s to %s" % (os.path.basename(mod.__file__), libpath))
++                        arc.write(mod.__file__, arcfnm)
++                    else:
++                        # The extension modules will be copied into
++                        # dlldir.  To be able to import it without dlldir
++                        # being on sys.path, create a loader module and
++                        # put that into the archive.
++                        pydfile = mod.__name__ + EXTENSION_SUFFIXES[0]
++                        if self.options.verbose > 1:
++                            print("Add Loader for %s to %s" % (os.path.basename(mod.__file__), libpath))
++                        loader = LOAD_FROM_DIR.format(pydfile)
++
++                        code = compile(loader, "<loader>", "exec",
++                                       optimize=self.options.optimize)
++                        if hasattr(mod, "__path__"):
++                            path = mod.__name__.replace(".", "\\") + "\\__init__" + bytecode_suffix
++                        else:
++                            path = mod.__name__.replace(".", "\\") + bytecode_suffix
++                        stream = io.BytesIO()
++                        stream.write(imp.get_magic())
++                        if sys.version_info >= (3,7,0):
++                            stream.write(b"\0\0\0\0") # null flags
++                        stream.write(b"\0\0\0\0") # null timestamp
++                        stream.write(b"\0\0\0\0") # null size
++                        marshal.dump(code, stream)
++                        arc.writestr(path, stream.getvalue())
++
++            if self.options.bundle_files == 0:
++                # put everything into the arc
++                files = self.mf.all_dlls()
++            elif self.options.bundle_files in (1, 2):
++                # put only extension dlls into the arc
++                files = self.mf.extension_dlls()
++            else:
++                arc.close()
++                return
+ 
+-        for src in files:
+-            if self.options.verbose > 1:
+-                print("Add DLL %s to %s" % (os.path.basename(src), libpath))
+-            arc.write(src, os.path.basename(src))
++            for src in files:
++                if self.options.verbose > 1:
++                    print("Add DLL %s to %s" % (os.path.basename(src), libpath))
++                arc.write(src, os.path.basename(src))
+ 
+-        arc.close()
++            arc.close()
+ 
+     def copy_files(self, destdir):
+         """Copy files (pyds, dlls, depending on the bundle_files value,
+@@ -498,17 +526,19 @@ class Runtime(object):
+             with UpdateResources(dst, delete_existing=False) as resource:
+                 resource.add_string(1000, "py2exe")
+ 
+-        if self.options.bundle_files == 3:
++        if not self.options.skip_archive and self.options.bundle_files == 3:
+             # copy extension modules; they go to libdir
+             for mod in self.mf.modules.values():
+                 if mod.__code__:
+                     # nothing to do for python modules.
+                     continue
+                 if hasattr(mod, "__file__"):
+-                    assert mod.__file__.endswith(EXTENSION_SUFFIXES[0])
+-                    pydfile = mod.__name__ + EXTENSION_SUFFIXES[0]
++                    if mod.__file__.endswith(EXTENSION_SUFFIXES[0]):
++                        pydfile = mod.__name__ + EXTENSION_SUFFIXES[0]
+ 
+-                    dst = os.path.join(libdir, pydfile)
++                        dst = os.path.join(libdir, pydfile)
++                    else:
++                        dst = os.path.join(libdir, os.path.basename(mod.__file__))
+                     if self.options.verbose:
+                         print("Copy %s to %s" % (mod.__file__, dst))
+                     shutil.copy2(mod.__file__, dst)
+@@ -638,9 +668,11 @@ def __load():
+     dllpath = os.path.join(os.path.dirname(__loader__.archive), r'{0}')
+     try:
+         mod = imp.load_dynamic(__name__, dllpath)
++        mod.frozen = 1
+     except ImportError as details:
+         raise ImportError('(%s) %r' % (details, dllpath)) from None
+-    mod.frozen = 1
++    except AttributeError:
++        pass
+ __load()
+ del __load
+ """
+diff --git a/setup.py b/setup.py
+index 342d194..5fb5a9a 100644
+--- a/setup.py
++++ b/setup.py
+@@ -12,6 +12,8 @@ if sys.version_info < (3, 3):
+ ############################################################################
+ 
+ from setuptools import setup
++from distutils import ccompiler
++isMingw32 = ccompiler.get_default_compiler()=='mingw32'
+ ##from distutils.core import setup
+ 
+ from py2exe.py2exe_distutils import Dist, Interpreter, BuildInterpreters
+@@ -26,11 +28,11 @@ def _is_debug_build():
+     return False
+ 
+ if _is_debug_build():
+-    macros = [("PYTHONDLL", '\\"python%d%d_d.dll\\"' % sys.version_info[:2]),
++    macros = [("PYTHONDLL", ('"libpython%d.%dm_d.dll"' if isMingw32 else '"\\python%d%d_d.dll\\"') % sys.version_info[:2]),
+ ##              ("PYTHONCOM", '\\"pythoncom%d%d_d.dll\\"' % sys.version_info[:2]),
+               ("_CRT_SECURE_NO_WARNINGS", '1')]
+ else:
+-    macros = [("PYTHONDLL", '\\"python%d%d.dll\\"' % sys.version_info[:2]),
++    macros = [("PYTHONDLL", ('"libpython%d.%dm.dll"' if isMingw32 else '"\\python%d%d.dll\\"') % sys.version_info[:2]),
+ ##              ("PYTHONCOM", '\\"pythoncom%d%d.dll\\"' % sys.version_info[:2]),
+               ("_CRT_SECURE_NO_WARNINGS", '1'),]
+ 
+@@ -39,9 +41,10 @@ macros.append(("Py_BUILD_CORE", '1'))
+ extra_compile_args = []
+ extra_link_args = []
+ 
+-extra_compile_args.append("-IC:\\Program Files\\Microsoft SDKs\\Windows\\v7.0\\Include")
+-extra_compile_args.append("-IC:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\include")
+-extra_compile_args.append("-IC:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.10586.0\\ucrt")
++if not isMingw32:
++    extra_compile_args.append("-IC:\\Program Files\\Microsoft SDKs\\Windows\\v7.0\\Include")
++    extra_compile_args.append("-IC:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\include")
++    extra_compile_args.append("-IC:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.10586.0\\ucrt")
+ 
+ if 0:
+     # enable this to debug a release build
+@@ -63,7 +66,11 @@ run_ctypes_dll = Interpreter("py2exe.run_ctypes_dll",
+                               "source/python-dynload.c",
+                               ],
+                              libraries=["user32", "shell32"],
+-                             export_symbols=["DllCanUnloadNow,PRIVATE",
++                             export_symbols=["DllCanUnloadNow",
++                                             "DllGetClassObject",
++                                             "DllRegisterServer",
++                                             "DllUnregisterServer",
++                                             ] if isMingw32 else ["DllCanUnloadNow,PRIVATE",
+                                              "DllGetClassObject,PRIVATE",
+                                              "DllRegisterServer,PRIVATE",
+                                              "DllUnregisterServer,PRIVATE",
+@@ -71,7 +78,7 @@ run_ctypes_dll = Interpreter("py2exe.run_ctypes_dll",
+                              target_desc = "shared_library",
+                              define_macros=macros,
+                              extra_compile_args=extra_compile_args,
+-                             extra_link_args=extra_link_args + ["/DLL"],
++                             extra_link_args=extra_link_args + ([] if isMingw32 else ["/DLL"]),
+                              )
+ 
+ run = Interpreter("py2exe.run",
+@@ -123,7 +130,7 @@ resource_dll = Interpreter("py2exe.resources",
+                            ["source/dll.c",
+                             "source/icon.rc"],
+                            target_desc = "shared_library",
+-                           extra_link_args=["/DLL"],
++                           extra_link_args=[] if isMingw32 else ["/DLL"],
+                            )
+ 
+ interpreters = [run, run_w, resource_dll,
+diff --git a/source/python-dynload.c b/source/python-dynload.c
+index 2a60b86..373bb62 100644
+--- a/source/python-dynload.c
++++ b/source/python-dynload.c
+@@ -31,7 +31,7 @@ static HMODULE hmod_pydll;
+ 
+ #define FUNC(res, name, args) \
+   static res(*proc)args; \
+-  if (!proc) (FARPROC)proc = MyGetProcAddress(hmod_pydll, #name)
++  if (!proc) proc = (res (*)args)MyGetProcAddress(hmod_pydll, #name)
+ 
+ #define DATA(type, name)				\
+   static type pflag; \
+@@ -158,7 +158,7 @@ void PyErr_Print(void)
+   proc();
+ }
+ 
+-void Py_SetProgramName(wchar_t *name)
++void Py_SetProgramName(const wchar_t *name)
+ {
+   FUNC(void, Py_SetProgramName, (wchar_t *));
+   proc(name);
+diff --git a/source/run.c b/source/run.c
+index e1f630e..933ae77 100644
+--- a/source/run.c
++++ b/source/run.c
+@@ -54,7 +54,11 @@ extern int start(int argc, wchar_t **argv);
+ /*
+   The main function for our exe.
+ */
++#if defined(__MINGW32__)
++int main (int argc, wchar_t **argv)
++#else
+ int wmain (int argc, wchar_t **argv)
++#endif
+ {
+ 	int result;
+ 	result = init("console_exe");
+diff --git a/source/start.c b/source/start.c
+index e894ae6..6b61624 100644
+--- a/source/start.c
++++ b/source/start.c
+@@ -128,7 +128,7 @@ BOOL locate_script(HMODULE hmod)
+ 		SystemError(GetLastError(), "Could not load script resource:");
+ 		return FALSE;
+ 	}
+-	p_script_info = (struct scriptinfo *)pScript = LockResource(hgbl);
++	p_script_info = (struct scriptinfo *)(pScript = LockResource(hgbl));
+ 	if (!pScript)  {
+ 		SystemError(GetLastError(), "Could not lock script resource:");
+ 		return FALSE;
+diff --git a/setup.py b/setup.py
+index 342d194..1fe1e43 100644
+--- a/setup.py
++++ b/setup.py
+@@ -107,7 +107,7 @@ run_w = Interpreter("py2exe.run_w",
+                     libraries=["user32", "shell32"],
+                     define_macros=macros,
+                     extra_compile_args=extra_compile_args,
+-                    extra_link_args=extra_link_args,
++                    extra_link_args=extra_link_args + (["-Wl,--subsystem,windows"] if isMingw32 else []),
+                     )
+ 
+ # The py2exe.resources name is special handled in BuildInterpreters;
Index: docker/msys/pywin32.patch
===================================================================
--- docker/msys/pywin32.patch	(revision 920)
+++ docker/msys/pywin32.patch	(revision 920)
@@ -0,0 +1,2641 @@
+diff --git a/com/win32com/src/ErrorUtils.cpp b/com/win32com/src/ErrorUtils.cpp
+index 1186cd1..314aff8 100644
+--- a/com/win32com/src/ErrorUtils.cpp
++++ b/com/win32com/src/ErrorUtils.cpp
+@@ -1118,9 +1118,15 @@ LPCTSTR GetScodeRangeString(HRESULT hr)
+ 		HRESULT hrLast;
+ 		LPCTSTR lpszName;
+ 	};
++#if defined(__MINGW32__)
++	#define MAKE_RANGE_ENTRY(hrRange) \
++                { static_cast<HRESULT>(hrRange##_FIRST), static_cast<HRESULT>(hrRange##_LAST), \
++			_T(#hrRange) _T("_FIRST...") _T(#hrRange) _T("_LAST") }
++#else
+ 	#define MAKE_RANGE_ENTRY(hrRange) \
+ 		{ hrRange##_FIRST, hrRange##_LAST, \
+ 			_T(#hrRange) _T("_FIRST...") _T(#hrRange) _T("_LAST") }
++#endif
+ 
+ 	static const RANGE_ENTRY hrRangeTable[] =
+ 	{
+diff --git a/com/win32com/src/PyGatewayBase.cpp b/com/win32com/src/PyGatewayBase.cpp
+index fc091cb..2ed9acc 100644
+--- a/com/win32com/src/PyGatewayBase.cpp
++++ b/com/win32com/src/PyGatewayBase.cpp
+@@ -7,6 +7,10 @@
+ 
+ #include "PythonCOMServer.h"
+ 
++#if defined(__MINGW32__)
++#include <algorithm>
++#endif
++
+ // {25D29CD0-9B98-11d0-AE79-4CF1CF000000}
+ extern const GUID IID_IInternalUnwrapPythonObject = 
+ 	{ 0x25d29cd0, 0x9b98, 0x11d0, { 0xae, 0x79, 0x4c, 0xf1, 0xcf, 0x0, 0x0, 0x0 } };
+@@ -437,7 +441,11 @@ static HRESULT invoke_setup(
+ 		// make sure its not a special DISPID we don't understand.
+ 		if (params->rgdispidNamedArgs[i] < 0)
+ 			return DISP_E_PARAMNOTFOUND;
++#if defined(__MINGW32__)
++		numArgs = std::max(numArgs, (UINT)params->rgdispidNamedArgs[i]+1);
++#else
+ 		numArgs = max(numArgs, (UINT)params->rgdispidNamedArgs[i]+1);
++#endif
+ 	}
+ 
+ 	PyObject *argList = PyTuple_New(numArgs);
+@@ -658,7 +666,11 @@ static HRESULT invoke_finish(
+ 			ob = NULL;
+ 			firstByRef = 1;
+ 		}
++#if defined(__MINGW32__)
++		UINT max_args = std::min(cUserResult-firstByRef, pDispParams->cArgs);
++#else
+ 		UINT max_args = min(cUserResult-firstByRef, pDispParams->cArgs);
++#endif
+ 		UINT *offsets = (UINT *)_malloca(sizeof(UINT) * max_args);
+ 		// Get the offsets into our params of all BYREF args, in order.
+ 		fill_byref_offsets(pDispParams, offsets, max_args);
+diff --git a/com/win32com/src/PythonCOM.cpp b/com/win32com/src/PythonCOM.cpp
+index da00839..67983a4 100644
+--- a/com/win32com/src/PythonCOM.cpp
++++ b/com/win32com/src/PythonCOM.cpp
+@@ -342,11 +342,13 @@ static PyObject *pythoncom_CoInitializeSecurity(PyObject *self, PyObject *args)
+ 			pSD = (PSECURITY_DESCRIPTOR)&appid;
+ 			}
+ 		}
++#if !defined(__MINGW32__)
+ 	else if (dwCapabilities & EOAC_ACCESS_CONTROL){
+ 		if (!PyCom_InterfaceFromPyObject(obSD, IID_IAccessControl, (void **)&pIAC, FALSE))
+ 			return NULL;
+ 		pSD = (PSECURITY_DESCRIPTOR)pIAC;
+ 		}
++#endif
+ 	else{
+ 		if (!PyWinObject_AsSECURITY_DESCRIPTOR(obSD, &pSD, /*BOOL bNoneOK = */TRUE))
+ 			return NULL;
+diff --git a/com/win32com/src/PythonCOM.def b/com/win32com/src/PythonCOM.def
+index 58d030f..6d2a54b 100644
+--- a/com/win32com/src/PythonCOM.def
++++ b/com/win32com/src/PythonCOM.def
+@@ -1,15 +1,15 @@
+ EXPORTS
+-	DllCanUnloadNow     @1 PRIVATE
+-	DllGetClassObject   @2 PRIVATE
++	DllCanUnloadNow
++	DllGetClassObject
+ 
+ 	; Some exports for clients who may "LoadLibrary"...
+-	PyCom_VariantFromPyObject
+-	PyCom_PyObjectFromVariant
+-	PyCom_InterfaceFromPyObject
+-	PyCom_PyObjectFromIUnknown
+-	PyCom_MakeOlePythonCall
++	_PyCom_VariantFromPyObject
++	_PyCom_PyObjectFromVariant
++	_PyCom_InterfaceFromPyObject
++	_PyCom_PyObjectFromIUnknown
++	_PyCom_MakeOlePythonCall
+ 
+-	PyCom_CoInitializeEx
+-	PyCom_CoInitialize
+-	PyCom_CoUninitialize
++	_PyCom_CoInitializeEx
++	_PyCom_CoInitialize
++	_PyCom_CoUninitialize
+ 
+diff --git a/com/win32com/src/Register.cpp b/com/win32com/src/Register.cpp
+index 0b24ee2..d259aff 100644
+--- a/com/win32com/src/Register.cpp
++++ b/com/win32com/src/Register.cpp
+@@ -322,7 +322,9 @@ static const PyCom_InterfaceSupportInfo g_interfaceSupportData[] =
+ 	PYCOM_INTERFACE_FULL	   ( CancelMethodCalls),
+ 	// No wrapper for IAccessControl yet, but you can still get the system implementation
+ 	//  by calling pythoncom.CoCreateInstance with IID_IUnknown as the returned interface
++#if !defined(__MINGW32__)
+ 	PYCOM_INTERFACE_CLSID_ONLY (DCOMAccessControl),
++#endif
+ 
+ 	// NULL, Unknown and dispatch special cases.
+ 	{ &IID_NULL, "Null", "IID_NULL", NULL, NULL},
+diff --git a/com/win32com/src/dllmain.cpp b/com/win32com/src/dllmain.cpp
+index fb81ddb..abf074c 100644
+--- a/com/win32com/src/dllmain.cpp
++++ b/com/win32com/src/dllmain.cpp
+@@ -175,6 +175,9 @@ typedef HRESULT (WINAPI *PFNCoInitializeEx)(LPVOID pvReserved, DWORD dwCoInit);
+ // the Init for Term function explicitely, and the framework will detect
+ // it no longer needs doing.
+ // XXX - Needs more thought about threading implications.
++#if defined(__MINGW32__)
++extern "C"
++#endif
+ HRESULT PyCom_CoInitializeEx(LPVOID reserved, DWORD dwInit)
+ {
+ 	// Must be thread-safe, although doesnt need the Python lock.
+diff --git a/com/win32com/src/include/PythonCOM.h b/com/win32com/src/include/PythonCOM.h
+index 9e422e4..f3b1063 100644
+--- a/com/win32com/src/include/PythonCOM.h
++++ b/com/win32com/src/include/PythonCOM.h
+@@ -111,10 +111,8 @@
+ #ifdef __MINGW32__
+ // Special Mingw32 considerations.
+ #define NO_PYCOM_IDISPATCHEX
+-#define NO_PYCOM_IPROVIDECLASSINFO
+ #define NO_PYCOM_ISERVICEPROVIDER
+ #define NO_PYCOM_ENUMSTATPROPSTG
+-#define NO_PYCOM_IPROPERTYSTORAGE
+ #define __try try
+ #define __except catch
+ #include <olectl.h>
+@@ -305,6 +303,9 @@ PYCOM_EXPORT PyObject *PyObject_FromOLEMENUGROUPWIDTHS(const OLEMENUGROUPWIDTHS
+ 
+ /* Functions for Initializing COM, and also letting the core know about it!
+ */
++#if defined(__MINGW32__)
++extern "C"
++#endif
+ PYCOM_EXPORT HRESULT PyCom_CoInitializeEx(LPVOID reserved, DWORD dwInit);
+ PYCOM_EXPORT HRESULT PyCom_CoInitialize(LPVOID reserved);
+ PYCOM_EXPORT void PyCom_CoUninitialize();
+diff --git a/com/win32com/src/initguid.cpp b/com/win32com/src/initguid.cpp
+new file mode 100644
+index 0000000..33d5923
+--- /dev/null
++++ b/com/win32com/src/initguid.cpp
+@@ -0,0 +1,7 @@
++#define INITGUID
++#undef _OBJIDLBASE_
++#define CINTERFACE
++#define USE_COM_CONTEXT_DEF
++#include <objidl.h>
++#include <ksguid.h>
++#include <ks.h>
+diff --git a/com/win32comext/axcontrol/src/PyIOleCommandTarget.cpp b/com/win32comext/axcontrol/src/PyIOleCommandTarget.cpp
+index 61bd706..e7908e9 100644
+--- a/com/win32comext/axcontrol/src/PyIOleCommandTarget.cpp
++++ b/com/win32comext/axcontrol/src/PyIOleCommandTarget.cpp
+@@ -4,6 +4,10 @@
+ #include "axcontrol_pch.h"
+ #include "PyIOleCommandTarget.h"
+ 
++#if defined(__MINGW32__)
++#include <algorithm>
++#endif
++
+ static BOOL FillOLECMDsWithSequence(OLECMD *pCmds, UINT ncmds, PyObject *obCmds)
+ {
+ 	for (UINT i=0;i<ncmds;i++) {
+@@ -211,7 +215,11 @@ STDMETHODIMP PyGOleCommandTarget::QueryStatus(
+ 			ok = PyWinObject_AsAutoFreeBstr(obText, &tempString);
+ 			if (ok) {
+ 				UINT strLen = SysStringLen(tempString);
++#if defined(__MINGW32__)
++				UINT nwrite = std::min((ULONG)strLen, pCmdText->cwBuf);
++#else
+ 				UINT nwrite = min(strLen, pCmdText->cwBuf);
++#endif
+ 				wcsncpy(pCmdText->rgwz, (WCHAR *)(BSTR)tempString,
+ 					nwrite);
+ 				pCmdText->cwActual = nwrite;
+diff --git a/com/win32comext/axcontrol/src/initguid.cpp b/com/win32comext/axcontrol/src/initguid.cpp
+new file mode 100644
+index 0000000..329e211
+--- /dev/null
++++ b/com/win32comext/axcontrol/src/initguid.cpp
+@@ -0,0 +1,8 @@
++#define INITGUID
++#undef _OBJIDLBASE_
++#define CINTERFACE
++#define USE_COM_CONTEXT_DEF
++#include <objidl.h>
++#include <ksguid.h>
++#include <ks.h>
++#include <docobj.h>
+diff --git a/com/win32comext/axscript/src/initguid.cpp b/com/win32comext/axscript/src/initguid.cpp
+new file mode 100644
+index 0000000..ba6baa3
+--- /dev/null
++++ b/com/win32comext/axscript/src/initguid.cpp
+@@ -0,0 +1,8 @@
++#define INITGUID
++#undef _OBJIDLBASE_
++#define CINTERFACE
++#define USE_COM_CONTEXT_DEF
++#include <objidl.h>
++#include <ksguid.h>
++#include <ks.h>
++#include <objsafe.h>
+diff --git a/com/win32comext/internet/src/PyIInternetProtocol.cpp b/com/win32comext/internet/src/PyIInternetProtocol.cpp
+index 43c25a8..b910c85 100644
+--- a/com/win32comext/internet/src/PyIInternetProtocol.cpp
++++ b/com/win32comext/internet/src/PyIInternetProtocol.cpp
+@@ -5,6 +5,10 @@
+ #include "PyIInternetProtocolRoot.h"
+ #include "PyIInternetProtocol.h"
+ 
++#if defined(__MINGW32__)
++#include <algorithm>
++#endif
++
+ // @doc - This file contains autoduck documentation
+ // ---------------------------------------------------
+ //
+@@ -181,7 +185,11 @@ STDMETHODIMP PyGInternetProtocol::Read(
+ 		hr = PyCom_HandlePythonFailureToCOM();
+ 	} else {
+ 		char *buf = PyString_AsString(result);
++#if defined(__MINGW32__)
++		*pcbRead = std::min(cb, (ULONG)PyString_Size(result));
++#else
+ 		*pcbRead = min(cb, (ULONG)PyString_Size(result));
++#endif
+ 		memcpy( pv, buf, *pcbRead);
+ 	}
+ 	return hr;
+diff --git a/com/win32comext/internet/src/PyIInternetProtocolInfo.cpp b/com/win32comext/internet/src/PyIInternetProtocolInfo.cpp
+index c00e43e..ef894ca 100644
+--- a/com/win32comext/internet/src/PyIInternetProtocolInfo.cpp
++++ b/com/win32comext/internet/src/PyIInternetProtocolInfo.cpp
+@@ -4,6 +4,10 @@
+ #include "internet_pch.h"
+ #include "PyIInternetProtocolInfo.h"
+ 
++#if defined(__MINGW32__)
++#include <algorithm>
++#endif
++
+ // @doc - This file contains autoduck documentation
+ // ---------------------------------------------------
+ //
+@@ -226,7 +230,11 @@ STDMETHODIMP PyGInternetProtocolInfo::ParseUrl(
+ 	if (!PyWinObject_AsBstr(result, &bstrTemp, FALSE, pcchResult)) bPythonIsHappy = FALSE;
+ 	if (!bPythonIsHappy) return PyCom_HandlePythonFailureToCOM(/*pexcepinfo*/);
+ 	++(*pcchResult); // Null terminator
++#if defined(__MINGW32__)
++	*pcchResult = std::min(*pcchResult, cchResult);
++#else
+ 	*pcchResult = min(*pcchResult, cchResult);
++#endif
+ 	memcpy(pwzResult, bstrTemp, *pcchResult * sizeof(WCHAR));
+ 	SysFreeString(bstrTemp);
+ 	Py_DECREF(result);
+@@ -258,7 +266,11 @@ STDMETHODIMP PyGInternetProtocolInfo::CombineUrl(
+ 	if (!PyWinObject_AsBstr(result, &bstrTemp, FALSE, pcchResult)) bPythonIsHappy = FALSE;
+ 	if (!bPythonIsHappy) hr = PyCom_HandlePythonFailureToCOM(/*pexcepinfo*/);
+ 	++(*pcchResult); // Null terminator
++#if defined(__MINGW32__)
++	*pcchResult = std::min(*pcchResult, cchResult);
++#else
+ 	*pcchResult = min(*pcchResult, cchResult);
++#endif
+ 	memcpy(pwzResult, bstrTemp, *pcchResult * sizeof(WCHAR));
+ 	SysFreeString(bstrTemp);
+ 	Py_DECREF(result);
+@@ -312,7 +324,11 @@ STDMETHODIMP PyGInternetProtocolInfo::QueryInfo(
+ 			return PyCom_HandlePythonFailureToCOM();
+ 		}
+ 	} else {
++#if defined(__MINGW32__)
++		*pcbBuf = std::min(cbBuffer, (ULONG)PyString_Size(result));
++#else
+ 		*pcbBuf = min(cbBuffer, (ULONG)PyString_Size(result));
++#endif
+ 		memcpy(pBuffer, PyString_AsString(result), *pcbBuf);
+ 	}
+ 	Py_DECREF(result);
+diff --git a/com/win32comext/internet/src/PyIInternetSecurityManager.cpp b/com/win32comext/internet/src/PyIInternetSecurityManager.cpp
+index 81439fc..a4cb106 100644
+--- a/com/win32comext/internet/src/PyIInternetSecurityManager.cpp
++++ b/com/win32comext/internet/src/PyIInternetSecurityManager.cpp
+@@ -4,6 +4,10 @@
+ #include "internet_pch.h"
+ #include "PyIInternetSecurityManager.h"
+ 
++#if defined(__MINGW32__)
++#include <algorithm>
++#endif
++
+ // @doc - This file contains autoduck documentation
+ // ---------------------------------------------------
+ //
+@@ -338,7 +342,11 @@ STDMETHODIMP PyGInternetSecurityManager::GetSecurityId(
+ 		Py_DECREF(result);
+ 		return MAKE_PYCOM_GATEWAY_FAILURE_CODE("GetSecurityId");
+ 	}
++#if defined(__MINGW32__)
++	*pcbSecurityId = std::min(buf_len, *pcbSecurityId);
++#else
+ 	*pcbSecurityId = min(buf_len, *pcbSecurityId);
++#endif
+ 	memcpy(pbSecurityId, buf, *pcbSecurityId);
+ 	Py_DECREF(result);
+ 	return hr;
+diff --git a/com/win32comext/internet/src/initguid.cpp b/com/win32comext/internet/src/initguid.cpp
+new file mode 100644
+index 0000000..1003585
+--- /dev/null
++++ b/com/win32comext/internet/src/initguid.cpp
+@@ -0,0 +1,9 @@
++#define INITGUID
++#undef _OBJIDLBASE_
++#define CINTERFACE
++#define USE_COM_CONTEXT_DEF
++#include <objidl.h>
++#include <ksguid.h>
++#include <ks.h>
++#include <urlmon.h>
++#include <mshtmhst.h>
+diff --git a/com/win32comext/propsys/src/PyPROPVARIANT.cpp b/com/win32comext/propsys/src/PyPROPVARIANT.cpp
+index b330129..694703f 100644
+--- a/com/win32comext/propsys/src/PyPROPVARIANT.cpp
++++ b/com/win32comext/propsys/src/PyPROPVARIANT.cpp
+@@ -3,7 +3,13 @@
+ 
+ #include "PythonCOM.h"
+ #include "PyPROPVARIANT.h"
++#if defined(__MINGW32__)
++extern "C" {
++#endif
+ #include "propvarutil.h"
++#if defined(__MINGW32__)
++}
++#endif
+ #include "float.h"
+ 
+ // @doc - This file contains autoduck documentation
+diff --git a/com/win32comext/propsys/src/propsys.cpp b/com/win32comext/propsys/src/propsys.cpp
+index ef0a2f4..69ff21f 100644
+--- a/com/win32comext/propsys/src/propsys.cpp
++++ b/com/win32comext/propsys/src/propsys.cpp
+@@ -279,6 +279,7 @@ static PyObject *PyPSGetItemPropertyHandler(PyObject *self, PyObject *args)
+ 	return PyCom_PyObjectFromIUnknown((IUnknown *)propertystore, riid, FALSE);
+ }
+ 
++#if !defined(__MINGW32__)
+ // @pymethod bytes|propsys|StgSerializePropVariant|Serializes a <o PyPROPVARIANT>
+ static PyObject *PyStgSerializePropVariant(PyObject *self, PyObject *args)
+ {
+@@ -319,6 +320,7 @@ static PyObject *PyStgDeserializePropVariant(PyObject *self, PyObject *args)
+ 		return PyCom_BuildPyException(hr);
+ 	return PyWinObject_FromPROPVARIANT(&pv);
+ };
++#endif
+ 
+ // @pymethod <o PyIPropertyStore>|propsys|PSCreateMemoryPropertyStore|Creates a temporary property store that is not connected to any backing storage
+ // @comm May also be used to create <o PyINamedPropertyStore>, <o PyIPropertyStoreCache>, <o PyIPersistStream>, or <o PyIPropertyBag>
+@@ -566,8 +568,10 @@ static struct PyMethodDef propsys_methods[]=
+ 	{ "PSRegisterPropertySchema", PyPSRegisterPropertySchema, 1 }, // @pymeth PSRegisterPropertySchema|Registers a group of properties described in a schema file
+ 	{ "PSUnregisterPropertySchema", PyPSUnregisterPropertySchema, 1 }, // @pymeth PSUnregisterPropertySchema|Removes a property schema definition
+ 	{ "SHGetPropertyStoreFromParsingName", PySHGetPropertyStoreFromParsingName, 1 }, // @pymeth SHGetPropertyStoreFromParsingName|Retrieves the property store for an item by path
++#if !defined(__MINGW32__)
+ 	{ "StgSerializePropVariant", PyStgSerializePropVariant, 1 }, // @pymeth StgSerializePropVariant|Serializes a <o PyPROPVARIANT>
+ 	{ "StgDeserializePropVariant", PyStgDeserializePropVariant, 1 }, // @pymeth StgDeserializePropVariant|Creates a <o PyPROPVARIANT> from a serialized buffer
++#endif
+ 	{ "PSCreateMemoryPropertyStore", PyPSCreateMemoryPropertyStore, 1 }, // @pymeth PSCreateMemoryPropertyStore|Creates a temporary property store that is not connected to any backing storage
+ 	{ "PSCreatePropertyStoreFromPropertySetStorage", PyPSCreatePropertyStoreFromPropertySetStorage, 1 }, // @pymeth PSCreatePropertyStoreFromPropertySetStorage|Wraps a <o PyIPropertySetStorage> interface in a <o PyIPropertyStore> object
+ 	{ "PSLookupPropertyHandlerCLSID", PyPSLookupPropertyHandlerCLSID, 1 }, // @pymeth PSLookupPropertyHandlerCLSID|Returns the GUID of the property handler for a file
+@@ -583,7 +587,7 @@ static struct PyMethodDef propsys_methods[]=
+ 	// MSDN says CLSID_PropertyChangeArray can be used to create IPropertyChangeArray, but
+ 	// I get "Class not registered".  Plus, it doesn't appear in any headers, although
+ 	// it's contained in uuid.lib.
+-#ifndef CLSID_PropertyChangeArray
++#if !defined(CLSID_PropertyChangeArray) && !defined(__MINGW32__)
+ 	EXTERN_C const CLSID CLSID_PropertyChangeArray;
+ #endif
+ 
+@@ -606,7 +610,9 @@ static const PyCom_InterfaceSupportInfo g_interfaceSupportData[] =
+ 	PYCOM_INTERFACE_CLIENT_ONLY (ObjectWithPropertyKey),
+ 	PYCOM_INTERFACE_CLIENT_ONLY (PropertyChange),
+ 	PYCOM_INTERFACE_CLIENT_ONLY (PropertyChangeArray),
++#if !defined(__MINGW32__)
+ 	PYCOM_INTERFACE_CLSID_ONLY (PropertyChangeArray),
++#endif
+ };
+ 
+ /* Module initialisation */
+diff --git a/com/win32comext/shell/src/PyICategoryProvider.cpp b/com/win32comext/shell/src/PyICategoryProvider.cpp
+index e2f2ea8..0ecf0cf 100644
+--- a/com/win32comext/shell/src/PyICategoryProvider.cpp
++++ b/com/win32comext/shell/src/PyICategoryProvider.cpp
+@@ -9,6 +9,10 @@
+ //
+ // Interface Implementation
+ 
++#if defined(__MINGW32__)
++__CRT_UUID_DECL(int, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
++#endif
++
+ PyICategoryProvider::PyICategoryProvider(IUnknown *pdisp):
+ 	PyIUnknown(pdisp)
+ {
+diff --git a/com/win32comext/shell/src/initguid.cpp b/com/win32comext/shell/src/initguid.cpp
+new file mode 100644
+index 0000000..8da5c87
+--- /dev/null
++++ b/com/win32comext/shell/src/initguid.cpp
+@@ -0,0 +1,11 @@
++#define INITGUID
++#undef _OBJIDLBASE_
++#define CINTERFACE
++#define USE_COM_CONTEXT_DEF
++#include <objidl.h>
++#include <ksguid.h>
++#include <ks.h>
++#include <shlguid.h>
++#include <shobjidl.h>
++#include <emptyvc.h>
++#include <_mingw.h>
+diff --git a/com/win32comext/shell/src/shell.cpp b/com/win32comext/shell/src/shell.cpp
+index 8b6e78c..f19a021 100644
+--- a/com/win32comext/shell/src/shell.cpp
++++ b/com/win32comext/shell/src/shell.cpp
+@@ -29,8 +29,10 @@ generates Windows .hlp files.
+ #include "PyIShellExtInit.h"
+ #include "PyIShellFolder.h"
+ #include "PyIShellFolder2.h"
++#if !defined(__MINGW32__)
+ #include "PyIEmptyVolumeCache.h"
+ #include "PyIEmptyVolumeCacheCallBack.h"
++#endif
+ #include "PyIEnumExplorerCommand.h"
+ #include "PyIEnumIDList.h"
+ #include "PyICopyHook.h"
+@@ -3606,12 +3608,16 @@ static const PyCom_InterfaceSupportInfo g_interfaceSupportData[] =
+ 	PYCOM_INTERFACE_FULL(ColumnProvider),
+ 	PYCOM_INTERFACE_CLIENT_ONLY(DefaultExtractIconInit),
+ 	PYCOM_INTERFACE_FULL(DropTargetHelper),
++#if !defined(__MINGW32__)
+ 	PYCOM_INTERFACE_CLIENT_ONLY(EmptyVolumeCacheCallBack),
++#endif
+ 	PYCOM_INTERFACE_CLIENT_ONLY(QueryAssociations),
+ 	PYCOM_INTERFACE_SERVER_ONLY(DeskBand),
+ 	PYCOM_INTERFACE_SERVER_ONLY(DockingWindow),
++#if !defined(__MINGW32__)
+ 	PYCOM_INTERFACE_SERVER_ONLY(EmptyVolumeCache),
+ 	PYCOM_INTERFACE_SERVER_ONLY(EmptyVolumeCache2),
++#endif
+ 	PYCOM_INTERFACE_CLIENT_ONLY(ExplorerBrowser),
+ 	PYCOM_INTERFACE_FULL(ExplorerBrowserEvents),
+ 	PYCOM_INTERFACE_FULL(ExplorerCommand),
+@@ -3850,12 +3856,16 @@ PYWIN_MODULE_INIT_FUNC(shell)
+ 	ADD_IID(FMTID_Briefcase);
+ 	ADD_IID(FMTID_Misc);
+ 	ADD_IID(FMTID_WebView);
++#if !defined(__MINGW32__)
+ 	ADD_IID(FMTID_AudioSummaryInformation);
++#endif
+ 	ADD_IID(FMTID_Volume);
+ 	ADD_IID(FMTID_Query);
++#if !defined(__MINGW32__)
+ 	ADD_IID(FMTID_SummaryInformation);
+ 	ADD_IID(FMTID_MediaFileSummaryInformation);
+ 	ADD_IID(FMTID_ImageSummaryInformation);
++#endif
+ 	ADD_IID(IID_CDefView);
+ 
+ 	ADD_IID(EP_NavPane);
+diff --git a/com/win32comext/taskscheduler/src/initguid.cpp b/com/win32comext/taskscheduler/src/initguid.cpp
+new file mode 100644
+index 0000000..d588502
+--- /dev/null
++++ b/com/win32comext/taskscheduler/src/initguid.cpp
+@@ -0,0 +1,8 @@
++#define INITGUID
++#undef _OBJIDLBASE_
++#define CINTERFACE
++#define USE_COM_CONTEXT_DEF
++#include <objidl.h>
++#include <ksguid.h>
++#include <ks.h>
++#include <mstask.h>
+diff --git a/isapi/src/Utils.cpp b/isapi/src/Utils.cpp
+index 8f278f2..b8976ae 100644
+--- a/isapi/src/Utils.cpp
++++ b/isapi/src/Utils.cpp
+@@ -127,7 +127,11 @@ static void CheckRegisterEventSourceFile()
+ 		return;
+ 
+ 	GetModuleFileNameW(g_hInstance, mod_name,
++#if defined(__MINGW32__)
++			  sizeof(mod_name)/sizeof(WCHAR));
++#else
+ 			  sizeof mod_name/sizeof WCHAR);
++#endif
+ 	if (!mod_name[0]) {
+ 		OutputDebugString(_T("GetModuleFileNameW failed!"));
+ 		return;
+@@ -160,6 +164,9 @@ static void CheckRegisterEventSourceFile()
+ }
+ 
+ // Write stuff to the event log.
++#if defined(__MINGW32__)
++extern "C"
++#endif
+ BOOL WriteEventLogMessage(WORD eventType, DWORD eventID, WORD num_inserts,
+                           const char **inserts)
+ {
+diff --git a/isapi/src/Utils.h b/isapi/src/Utils.h
+index 3779ca9..f076826 100644
+--- a/isapi/src/Utils.h
++++ b/isapi/src/Utils.h
+@@ -58,6 +58,9 @@ char *HTMLErrorResp(const char *msg);
+ TCHAR *GetModulePath(void);
+ 
+ // Write entry to the event log
++#if defined(__MINGW32__)
++extern "C"
++#endif
+ BOOL WriteEventLogMessage(WORD eventType, DWORD eventID, WORD num_inserts,
+                           const char **inserts);
+ 
+diff --git a/isapi/src/pyISAPI.cpp b/isapi/src/pyISAPI.cpp
+index 439d3ca..2c94610 100644
+--- a/isapi/src/pyISAPI.cpp
++++ b/isapi/src/pyISAPI.cpp
+@@ -52,6 +52,9 @@ char g_CallbackModuleName[_MAX_PATH + _MAX_FNAME] = "";
+ #define TRACE(x) OutputDebugString(_T(x))
+ 
+ // This is an entry point for py2exe.
++#if defined(__MINGW32__)
++extern "C"
++#endif
+ void WINAPI PyISAPISetOptions(const char *modname, BOOL is_frozen)
+ {
+ 	strncpy(g_CallbackModuleName, modname,
+diff --git a/setup.py b/setup.py
+index 7c35d90..5872968 100644
+--- a/setup.py
++++ b/setup.py
+@@ -72,6 +72,8 @@ import shutil
+ 
+ is_py3k = sys.version_info > (3,) # get this out of the way early on...
+ 
++build_mingw32=True
++
+ try:
+     import winreg # py3k
+ except ImportError:
+@@ -140,6 +142,10 @@ dll_base_address = 0x1e200000
+ def find_platform_sdk_dir():
+     # The user might have their current environment setup for the
+     # SDK, in which case "MSSDK_INCLUDE" and "MSSDK_LIB" vars must be set.
++    if build_mingw32:
++        return { "include": ["c:/msys64/mingw32/include", "c:/msys64/mingw32/i686-w64-mingw32/include"], 
++	         "lib": ["c:/msys64/mingw32/lib", "c:/msys64//mingw32/i686-w64-mingw32/lib"] }
++
+     if "MSSDK_INCLUDE" in os.environ and "MSSDK_LIB" in os.environ:
+         print("Using SDK as specified in the environment")
+         return {
+@@ -173,9 +179,10 @@ def find_platform_sdk_dir():
+ # to prevent the extension from loading.  For more details, see
+ # http://bugs.python.org/issue7833 (which has landed for Python 2.7 and on 3.2
+ # and later, which are all we care about currently)
+-from distutils.msvc9compiler import MSVCCompiler
+-MSVCCompiler._orig_spawn = MSVCCompiler.spawn
+-MSVCCompiler._orig_link = MSVCCompiler.link
++if not build_mingw32:
++    from distutils.msvc9compiler import MSVCCompiler
++    MSVCCompiler._orig_spawn = MSVCCompiler.spawn
++    MSVCCompiler._orig_link = MSVCCompiler.link
+ 
+ # We need to override this method for versions where issue7833 *has* landed
+ # (ie, 2.7 and 3.2+)
+@@ -195,7 +202,8 @@ def manifest_get_embed_info(self, target_desc, ld_args):
+ 
+ # always monkeypatch it in even though it will only be called in 2.7
+ # and 3.2+.
+-MSVCCompiler.manifest_get_embed_info = manifest_get_embed_info
++if not build_mingw32:
++    MSVCCompiler.manifest_get_embed_info = manifest_get_embed_info
+ 
+ def monkeypatched_spawn(self, cmd):
+     is_link = cmd[0].endswith("link.exe") or cmd[0].endswith('"link.exe"')
+@@ -239,8 +247,9 @@ def monkeypatched_link(self, target_desc, objects, output_filename, *args, **kw)
+         return self._orig_link(target_desc, objects, output_filename, *args, **kw)
+     finally:
+         delattr(self, '_want_assembly_kept')
+-MSVCCompiler.spawn = monkeypatched_spawn
+-MSVCCompiler.link = monkeypatched_link
++if not build_mingw32:
++    MSVCCompiler.spawn = monkeypatched_spawn
++    MSVCCompiler.link = monkeypatched_link
+ 
+ 
+ sdk_info = find_platform_sdk_dir()
+@@ -449,6 +458,18 @@ class WinExt (Extension):
+                 # Unicode, Windows executables seem to need this magic:
+                 if "/SUBSYSTEM:WINDOWS" in self.extra_link_args:
+                     self.extra_link_args.append("/ENTRY:wWinMainCRTStartup")
++        else:
++            self.extra_compile_args.append("-fpermissive")
++            unicode_mode = self.unicode_mode
++            if unicode_mode is None:
++                unicode_mode = is_py3k
++            if unicode_mode:
++                self.extra_compile_args.append("-DUNICODE")
++                self.extra_compile_args.append("-D_UNICODE")
++                self.extra_compile_args.append("-DWINNT")
++                # Unicode, Windows executables seem to need this magic:
++                #if "/SUBSYSTEM:WINDOWS" in self.extra_link_args:
++                #    self.extra_link_args.append("/ENTRY:wWinMainCRTStartup")
+ 
+ class WinExt_pythonwin(WinExt):
+     def __init__ (self, name, **kw):
+@@ -641,7 +662,7 @@ class my_build_ext(build_ext):
+         # The pywintypes library is created in the build_temp
+         # directory, so we need to add this to library_dirs
+         self.library_dirs.append(self.build_temp)
+-        self.mingw32 = (self.compiler == "mingw32")
++        self.mingw32 = build_mingw32
+         if self.mingw32:
+             self.libraries.append("stdc++")
+ 
+@@ -698,7 +719,8 @@ class my_build_ext(build_ext):
+             self.compiler.add_include_dir(extra)
+         # and again for lib dirs.
+         for extra in sdk_info["lib"]:
+-            extra = os.path.join(extra, 'x64' if is_64bit else 'x86')
++            if not build_mingw32:
++                extra = os.path.join(extra, 'x64' if is_64bit else 'x86')
+             assert os.path.isdir(extra), extra
+             assert extra not in self.library_dirs # see above
+             assert os.path.isdir(extra), "%s doesn't exist!" % (extra,)
+@@ -714,7 +736,7 @@ class my_build_ext(build_ext):
+         # includes interfaces for 64-bit builds.
+         if self.plat_name == 'win-amd64' and ext.name == 'exchdapi':
+             return "No 64-bit library for utility functions available."
+-        if get_build_version() >=14:
++        if not build_mingw32 and get_build_version() >=14:
+             if ext.name == 'exchange':
+                 ext.libraries.append('legacy_stdio_definitions')
+             elif ext.name == 'exchdapi':
+@@ -758,7 +780,8 @@ class my_build_ext(build_ext):
+ 
+         # We update the .libraries list with the resolved library name.
+         # This is really only so "_d" works.
+-        ext.libraries = patched_libs
++        if not build_mingw32:
++            ext.libraries = patched_libs
+         return None # no reason - it can be built!
+ 
+     def _build_scintilla(self):
+@@ -972,11 +995,16 @@ class my_build_ext(build_ext):
+         if sys.version_info > (2, 7) and sys.version_info < (3, 3):
+             # only stuff built with msvc9 needs this loader.
+             self._build_pycom_loader()
+-        self._build_scintilla()
++        if not build_mingw32:
++            self._build_scintilla()
+         # Copy cpp lib files needed to create Python COM extensions
+-        clib_files = (['win32', 'pywintypes%s.lib'],
+-                      ['win32com', 'pythoncom%s.lib'],
+-                      ['win32com', 'axscript%s.lib'])
++        if build_mingw32:
++            clib_files = (['win32', 'libpywintypes%s.a'],
++                          ['win32com', 'libpythoncom%s.a'])
++        else:
++            clib_files = (['win32', 'pywintypes%s.lib'],
++                          ['win32com', 'pythoncom%s.lib'],
++                          ['win32com', 'axscript%s.lib'])
+         for clib_file in clib_files:
+             target_dir = os.path.join(self.build_lib, clib_file[0], "libs")
+             if not os.path.exists(target_dir):
+@@ -988,6 +1016,8 @@ class my_build_ext(build_ext):
+             self.copy_file(os.path.join(self.build_temp, fname),
+                            target_dir
+                            )
++        if build_mingw32:
++            return
+         # The MFC DLLs.
+         target_dir = os.path.join(self.build_lib, "pythonwin")
+ 
+@@ -1081,9 +1111,13 @@ class my_build_ext(build_ext):
+         # this, distutils gets confused, as they both try and use the same
+         # .obj.
+         output_dir = os.path.join(self.build_temp, ext.name)
++        if build_mingw32:
++            include_dirs = [output_dir, os.path.join(output_dir, "win32", "src")] + ext.include_dirs
++        else:
++            include_dirs = ext.include_dirs
+         kw = {'output_dir': output_dir,
+               'macros': macros,
+-              'include_dirs': ext.include_dirs,
++              'include_dirs': include_dirs,
+               'debug': self.debug,
+               'extra_postargs': extra_args,
+               'depends': ext.depends,
+@@ -1115,6 +1149,7 @@ class my_build_ext(build_ext):
+                'extra_postargs': extra_args,
+                'debug': self.debug,
+                'build_temp': self.build_temp,
++               'extra_preargs': []
+         }
+ 
+         # Detect target language, if not provided
+@@ -1162,22 +1197,37 @@ class my_build_ext(build_ext):
+         old_build_temp = self.build_temp
+         want_static_crt = sys.version_info > (2,6) and ext.name in static_crt_modules
+         if want_static_crt:
+-            self.compiler.compile_options.remove('/MD')
+-            self.compiler.compile_options.append('/MT')
+-            self.compiler.compile_options_debug.remove('/MDd')
+-            self.compiler.compile_options_debug.append('/MTd')
++            if not build_mingw32:
++                self.compiler.compile_options.remove('/MD')
++                self.compiler.compile_options.append('/MT')
++                self.compiler.compile_options_debug.remove('/MDd')
++                self.compiler.compile_options_debug.append('/MTd')
+ 
+         try:
++            if build_mingw32:
++                incs = set()
++                for source in ext.sources:
++                    output_dir = os.path.join(self.build_temp, os.path.dirname(source))
++                    if output_dir not in incs:
++                        ext.include_dirs.append(output_dir)
++                        incs.add(output_dir)
+             build_ext.build_extension(self, ext)
+             # XXX This has to be changed for mingw32
+             # Get the .lib files we need.  This is limited to pywintypes,
+             # pythoncom and win32ui - but the first 2 have special names
+-            extra = self.debug and "_d.lib" or ".lib"
++            if build_mingw32:
++                extra = self.debug and "_d.a" or ".a"
++            else:
++                extra = self.debug and "_d.lib" or ".lib"
+             if ext.name in ("pywintypes", "pythoncom"):
+                 # The import libraries are created as PyWinTypes23.lib, but
+                 # are expected to be pywintypes.lib.
+-                name1 = "%s%d%d%s" % (ext.name, sys.version_info[0], sys.version_info[1], extra)
+-                name2 = "%s%s" % (ext.name, extra)
++                if build_mingw32:
++                    name1 = "lib%s%d%d%s" % (ext.name, sys.version_info[0], sys.version_info[1], extra)
++                    name2 = "lib%s%s" % (ext.name, extra)
++                else:
++                    name1 = "%s%d%d%s" % (ext.name, sys.version_info[0], sys.version_info[1], extra)
++                    name2 = "%s%s" % (ext.name, extra)
+             elif ext.name in ("win32ui",):
+                 name1 = name2 = ext.name + extra
+             else:
+@@ -1199,10 +1249,11 @@ class my_build_ext(build_ext):
+         finally:
+             self.build_temp = old_build_temp
+             if want_static_crt:
+-                self.compiler.compile_options.remove('/MT')
+-                self.compiler.compile_options.append('/MD')
+-                self.compiler.compile_options_debug.remove('/MTd')
+-                self.compiler.compile_options_debug.append('/MDd')
++                if not build_mingw32:
++                    self.compiler.compile_options.remove('/MT')
++                    self.compiler.compile_options.append('/MD')
++                    self.compiler.compile_options_debug.remove('/MTd')
++                    self.compiler.compile_options_debug.append('/MDd')
+ 
+     def get_ext_filename(self, name):
+         # The pywintypes and pythoncom extensions have special names
+@@ -1298,6 +1349,8 @@ class my_build_ext(build_ext):
+         for source in swig_sources:
+             swig_cmd = [swig, "-python", "-c++"]
+             swig_cmd.append("-dnone",) # we never use the .doc files.
++            if not build_mingw32:
++                swig_cmd.append("-I" + os.path.abspath("swig/swig_lib/python"))
+             swig_cmd.extend(self.current_extension.extra_swig_commands)
+             if not is_py3k:
+                 swig_cmd.append("-DSWIG_PY2K")
+@@ -1368,7 +1421,10 @@ class my_install(install):
+         if not self.dry_run and not self.root:
+             # We must run the script we just installed into Scripts, as it
+             # may have had 2to3 run over it.
+-            filename = os.path.join(self.prefix, "Scripts", "pywin32_postinstall.py")
++            if build_mingw32:
++                filename = os.path.join(self.prefix, "bin", "pywin32_postinstall.py")
++            else:
++                filename = os.path.join(self.prefix, "Scripts", "pywin32_postinstall.py")
+             if not os.path.isfile(filename):
+                 raise RuntimeError("Can't find '%s'" % (filename,))
+             print("Executing post install script...")
+@@ -1388,18 +1444,25 @@ def my_new_compiler(**kw):
+     return orig_new_compiler(**kw)
+ 
+ # No way to cleanly wedge our compiler sub-class in.
+-from distutils import ccompiler, msvccompiler
++from distutils import ccompiler
+ orig_new_compiler = ccompiler.new_compiler
+ ccompiler.new_compiler = my_new_compiler
+ 
+-base_compiler = msvccompiler.MSVCCompiler
++if build_mingw32:
++    from distutils import cygwinccompiler
++    base_compiler = cygwinccompiler.Mingw32CCompiler
++else:
++    from distutils import msvccompiler
++    base_compiler = msvccompiler.MSVCCompiler
++
+ 
+ class my_compiler(base_compiler):
+     # Just one GUIDS.CPP and it gives trouble on mainwin too. Maybe I
+     # should just rename the file, but a case-only rename is likely to be
+     # worse!  This can probably go away once we kill the VS project files
+     # though, as we can just specify the lowercase name in the module def.
+-    _cpp_extensions = base_compiler._cpp_extensions + [".CPP"]
++    if not build_mingw32:
++        _cpp_extensions = base_compiler._cpp_extensions + [".CPP"]
+     src_extensions = base_compiler.src_extensions + [".CPP"]
+ 
+     def link(self,
+@@ -1411,17 +1474,41 @@ class my_compiler(base_compiler):
+               library_dirs=None,
+               runtime_library_dirs=None,
+               export_symbols=None,
+-              debug=0, *args, **kw):
+-        msvccompiler.MSVCCompiler.link( self,
+-                                        target_desc,
+-                                        objects,
+-                                        output_filename,
+-                                        output_dir,
+-                                        libraries,
+-                                        library_dirs,
+-                                        runtime_library_dirs,
+-                                        export_symbols,
+-                                        debug, *args, **kw)
++              debug=0, extra_preargs = None, *args, **kw):
++        if build_mingw32:
++            temp_dir = os.path.dirname(objects[0])
++            dll_name = os.path.splitext(os.path.basename(output_filename))[0]
++            lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a")
++            implib_arg="-Wl,--out-implib,%s" % lib_file
++
++            if extra_preargs:
++                extra_preargs.extend(implib_arg)
++            else:
++                extra_preargs = [implib_arg]
++
++            cygwinccompiler.Mingw32CCompiler.link( self,
++                                                   target_desc,
++                                                   objects,
++                                                   output_filename,
++                                                   output_dir,
++                                                   libraries,
++                                                   library_dirs,
++                                                   runtime_library_dirs,
++                                                   export_symbols,
++                                                   debug, extra_preargs,
++                                                   *args, **kw)
++        else:
++            msvccompiler.MSVCCompiler.link( self,
++                                            target_desc,
++                                            objects,
++                                            output_filename,
++                                            output_dir,
++                                            libraries,
++                                            library_dirs,
++                                            runtime_library_dirs,
++                                            export_symbols,
++                                            debug, *args, **kw)
++
+         # Here seems a good place to stamp the version of the built
+         # target.  Do this externally to avoid suddenly dragging in the
+         # modules needed by this process, and which we will soon try and
+@@ -1457,6 +1544,45 @@ class my_compiler(base_compiler):
+         if not ok:
+             log.info('Unable to import verstamp, no version info will be added')
+ 
++    if build_mingw32:
++        def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
++            if ext == ".mc":
++                try:
++                    basename=os.path.basename(src)[:-3]
++                    outdir=os.path.dirname(obj)
++                    self.spawn(["windmc", "-h", outdir, "-r", outdir, src])
++                    self.spawn(["windres", "-i", 
++                                os.path.join(outdir, basename + ".rc"),
++                                "-o", obj])
++                except DistutilsExecError as msg:
++                    raise CompileError(msg)
++            else:
++                cygwinccompiler.Mingw32CCompiler._compile(self,
++                                                          obj, src, ext, cc_args,
++                                                          extra_postargs, pp_opts)
++
++        def object_filenames(self, source_filenames, strip_dir=0, output_dir=''):
++            unproc_src_names = []
++            obj_names = []
++            for src_name in source_filenames:
++                base, ext = os.path.splitext(src_name)
++                if ext==".mc":
++                    if unproc_src_names:
++                        obj_names.extend(cygwinccompiler.Mingw32CCompiler.\
++                            object_filenames(self, unproc_src_names,
++                                             strip_dir = strip_dir,
++                                             output_dir = output_dir))
++                        unproc_src_names = []
++                    obj_names.append (os.path.join(output_dir,
++                                      base + ext + self.obj_extension))
++                else:
++                    unproc_src_names.append(src_name)
++            if unproc_src_names:
++                obj_names.extend(cygwinccompiler.Mingw32CCompiler.\
++                    object_filenames(self, unproc_src_names, strip_dir = strip_dir,
++                                     output_dir = output_dir))
++            return obj_names
++
+ 
+ ################################################################
+ 
+@@ -1550,7 +1676,7 @@ for info in (
+             win32/src/win32crypt/PyCRYPTPROV.cpp
+             win32/src/win32crypt/PyCTL_CONTEXT.cpp
+             """),
+-        ("win32file", "", None, 0x0500, """
++        ("win32file", "wsock32 ws2_32" if build_mingw32 else "", None, 0x0500, """
+               win32/src/win32file.i
+               win32/src/win32file_comm.cpp
+               """),
+@@ -1607,7 +1733,7 @@ for info in (
+         sources = info[4].split()
+     extra_compile_args = []
+     ext = WinExt_win32(name,
+-                 libraries=lib_names,
++                 libraries=lib_names + (" pywintypes" if build_mingw32 else ""),
+                  extra_compile_args = extra_compile_args,
+                  windows_h_version = windows_h_ver,
+                  sources = sources,
+@@ -1620,7 +1746,7 @@ win32_extensions += [
+             sources = """
+                 win32\\src\\win32evtlog_messages.mc win32\\src\\win32evtlog.i
+                 """.split(),
+-                libraries="advapi32 oleaut32",
++                libraries="advapi32 oleaut32" + (" pywintypes" if build_mingw32 else ""),
+                 delay_load_libraries="wevtapi",
+                 windows_h_version=0x0600
+         ),
+@@ -1628,7 +1754,7 @@ win32_extensions += [
+            sources = """
+                 win32/src/win32apimodule.cpp win32/src/win32api_display.cpp
+                 """.split(),
+-           libraries="user32 advapi32 shell32 version",
++                 libraries="user32 advapi32 shell32 version" + (" pywintypes" if build_mingw32 else ""),
+            delay_load_libraries="powrprof",
+            windows_h_version=0x0500,
+         ),
+@@ -1638,7 +1764,7 @@ win32_extensions += [
+                 win32/src/win32gui.i
+                """.split(),
+            windows_h_version=0x0500,
+-           libraries="gdi32 user32 comdlg32 comctl32 shell32",
++           libraries="gdi32 user32 comdlg32 comctl32 shell32" + (" pywintypes" if build_mingw32 else ""),
+            define_macros = [("WIN32GUI", None)],
+         ),
+     # winxpgui is built from win32gui.i, but sets up different #defines before
+@@ -1648,7 +1774,7 @@ win32_extensions += [
+                 win32/src/winxpgui.rc win32/src/win32dynamicdialog.cpp
+                 win32/src/win32gui.i
+                """.split(),
+-           libraries="gdi32 user32 comdlg32 comctl32 shell32",
++           libraries="gdi32 user32 comdlg32 comctl32 shell32" + (" pywintypes" if build_mingw32 else ""),
+            windows_h_version=0x0500,
+            define_macros = [("WIN32GUI",None), ("WINXPGUI",None)],
+            extra_swig_commands=["-DWINXPGUI"],
+@@ -1656,7 +1782,7 @@ win32_extensions += [
+     # winxptheme
+     WinExt_win32("_winxptheme",
+            sources = ["win32/src/_winxptheme.i"],
+-           libraries="gdi32 user32 comdlg32 comctl32 shell32 Uxtheme",
++           libraries="gdi32 user32 comdlg32 comctl32 shell32 Uxtheme" + (" pywintypes" if build_mingw32 else ""),
+            windows_h_version=0x0500,
+         ),
+ ]
+@@ -1664,7 +1790,7 @@ win32_extensions += [
+     WinExt_win32('servicemanager',
+            sources = ["win32/src/PythonServiceMessages.mc", "win32/src/PythonService.cpp"],
+            extra_compile_args = ['-DPYSERVICE_BUILD_DLL'],
+-           libraries = "user32 ole32 advapi32 shell32",
++           libraries = "user32 ole32 advapi32 shell32" + (" pywintypes" if build_mingw32 else ""),
+            windows_h_version = 0x500,
+            unicode_mode=True,),
+ ]
+@@ -1695,7 +1821,8 @@ dirs = {
+ 
+ # The COM modules.
+ pythoncom = WinExt_system32('pythoncom',
+-                   sources=("""
++                   sources=((("%(win32com)s/initguid.cpp"  if build_mingw32 else "") +
++                        """
+                         %(win32com)s/dllmain.cpp            %(win32com)s/ErrorUtils.cpp
+                         %(win32com)s/MiscTypes.cpp          %(win32com)s/oleargs.cpp
+                         %(win32com)s/PyComHelpers.cpp       %(win32com)s/PyFactory.cpp
+@@ -1737,7 +1864,7 @@ pythoncom = WinExt_system32('pythoncom',
+                         %(win32com)s/extensions/PyICancelMethodCalls.cpp    %(win32com)s/extensions/PyIContext.cpp
+                         %(win32com)s/extensions/PyIEnumContextProps.cpp     %(win32com)s/extensions/PyIClientSecurity.cpp
+                         %(win32com)s/extensions/PyIServerSecurity.cpp
+-                        """ % dirs).split(),
++                        """) % dirs).split(),
+                    depends=("""
+                         %(win32com)s/include\\propbag.h          %(win32com)s/include\\PyComTypeObjects.h
+                         %(win32com)s/include\\PyFactory.h        %(win32com)s/include\\PyGConnectionPoint.h
+@@ -1763,7 +1890,7 @@ pythoncom = WinExt_system32('pythoncom',
+                         %(win32com)s/include\\PyIEnumContextProps.h     %(win32com)s/include\\PyIClientSecurity.h
+                         %(win32com)s/include\\PyIServerSecurity.h
+                         """ % dirs).split(),
+-                   libraries = "oleaut32 ole32 user32 urlmon",
++                   libraries = "oleaut32 ole32 user32 urlmon uuid" + (" pywintypes" if build_mingw32 else ""),
+                    export_symbol_file = 'com/win32com/src/PythonCOM.def',
+                    extra_compile_args = ['-DBUILD_PYTHONCOM'],
+                    pch_header = "stdafx.h",
+@@ -1788,7 +1915,7 @@ com_extensions += [
+                         %(adsi)s/PyIADs.cpp
+                         """ % dirs).split()),
+     WinExt_win32com('axcontrol', pch_header="axcontrol_pch.h",
+-                    sources=("""
++                    sources=(("""
+                         %(axcontrol)s/AXControl.cpp
+                         %(axcontrol)s/PyIOleControl.cpp          %(axcontrol)s/PyIOleControlSite.cpp
+                         %(axcontrol)s/PyIOleInPlaceActiveObject.cpp
+@@ -1799,10 +1926,11 @@ com_extensions += [
+                         %(axcontrol)s/PyIOleClientSite.cpp       %(axcontrol)s/PyIOleInPlaceSite.cpp
+                         %(axcontrol)s/PyIOleObject.cpp           %(axcontrol)s/PyIViewObject2.cpp
+                         %(axcontrol)s/PyIOleCommandTarget.cpp
+-                        """ % dirs).split()),
++                        """ + ("%(axcontrol)s/initguid.cpp" if build_mingw32 else "")) % dirs).split(),
++                        libraries="pythoncom pywintypes"),
+     WinExt_win32com('axscript',
+-                    sources=("""
+-                        %(axscript)s/AXScript.cpp
++                    sources=(("""
++                        %(axscript)s/AXScript.cpp                %(axscript)s/initguid.cpp
+                         %(axscript)s/GUIDS.CPP                   %(axscript)s/PyGActiveScript.cpp
+                         %(axscript)s/PyGActiveScriptError.cpp    %(axscript)s/PyGActiveScriptParse.cpp
+                         %(axscript)s/PyGActiveScriptSite.cpp     %(axscript)s/PyGObjectSafety.cpp
+@@ -1810,7 +1938,7 @@ com_extensions += [
+                         %(axscript)s/PyIActiveScriptParse.cpp    %(axscript)s/PyIActiveScriptParseProcedure.cpp
+                         %(axscript)s/PyIActiveScriptSite.cpp     %(axscript)s/PyIMultiInfos.cpp
+                         %(axscript)s/PyIObjectSafety.cpp         %(axscript)s/stdafx.cpp
+-                        """ % dirs).split(),
++                        """ + ("%(axscript)s/initguid.cpp" if build_mingw32 else "")) % dirs).split(),
+                     depends=("""
+                              %(axscript)s/AXScript.h
+                              %(axscript)s/guids.h                %(axscript)s/PyGActiveScriptError.h
+@@ -1820,7 +1948,8 @@ com_extensions += [
+                              """ % dirs).split(),
+                     extra_compile_args = ['-DPY_BUILD_AXSCRIPT'],
+                     implib_name="axscript",
+-                    pch_header = "stdafx.h"
++                    pch_header = "stdafx.h",
++                    libraries="pythoncom pywintypes" if build_mingw32 else ""
+     ),
+     WinExt_win32com('axdebug',
+             libraries="axscript",
+@@ -1870,17 +1999,17 @@ com_extensions += [
+                     %(axdebug)s/PyIRemoteDebugApplicationEvents.cpp
+                     %(axdebug)s/PyIRemoteDebugApplicationThread.cpp
+                     %(axdebug)s/stdafx.cpp
+-                     """ % dirs).split(),
+-    ),
++                     """ % dirs).split() ),
+     WinExt_win32com('internet', pch_header="internet_pch.h",
+-                    sources=("""
++                    sources=(("""
+                         %(internet)s/internet.cpp                   %(internet)s/PyIDocHostUIHandler.cpp
+                         %(internet)s/PyIHTMLOMWindowServices.cpp    %(internet)s/PyIInternetBindInfo.cpp
+                         %(internet)s/PyIInternetPriority.cpp        %(internet)s/PyIInternetProtocol.cpp
+                         %(internet)s/PyIInternetProtocolInfo.cpp    %(internet)s/PyIInternetProtocolRoot.cpp
+                         %(internet)s/PyIInternetProtocolSink.cpp    %(internet)s/PyIInternetSecurityManager.cpp
+-                    """ % dirs).split(),
+-                    depends=["%(internet)s/internet_pch.h" % dirs]),
++                    """ + ("%(internet)s/initguid.cpp"  if build_mingw32 else "")) % dirs).split(),
++                    depends=["%(internet)s/internet_pch.h" % dirs],
++                    libraries="pythoncom pywintypes" if build_mingw32 else ""),
+     WinExt_win32com('mapi', libraries="advapi32", pch_header="PythonCOM.h",
+                     include_dirs=["%(mapi)s/mapi_headers" % dirs],
+                     optional_headers=['edkmdb.h', 'edkguid.h'],
+@@ -1929,9 +2058,10 @@ com_extensions += [
+                                   %(mapi)s/mapi_stub_library/MapiStubLibrary.cpp
+                                   %(mapi)s/mapi_stub_library/StubUtils.cpp
+                                   """ % dirs).split()),
+-    WinExt_win32com('shell', libraries='shell32', pch_header="shell_pch.h",
++
++    WinExt_win32com('shell', libraries=('pythoncom pywintypes ' if build_mingw32 else '') + 'shell32', pch_header="shell_pch.h",
+                     windows_h_version = 0x600,
+-                    sources=("""
++                    sources=(("""
+                         %(shell)s/PyIActiveDesktop.cpp
+                         %(shell)s/PyIApplicationDestinations.cpp
+                         %(shell)s/PyIApplicationDocumentLists.cpp
+@@ -1956,8 +2086,6 @@ com_extensions += [
+                         %(shell)s/PyIEnumObjects.cpp
+                         %(shell)s/PyIEnumResources.cpp
+                         %(shell)s/PyIEnumShellItems.cpp
+-                        %(shell)s/PyIEmptyVolumeCache.cpp
+-                        %(shell)s/PyIEmptyVolumeCacheCallBack.cpp
+                         %(shell)s/PyIExplorerBrowser.cpp
+                         %(shell)s/PyIExplorerBrowserEvents.cpp
+                         %(shell)s/PyIExplorerCommand.cpp
+@@ -2002,8 +2130,9 @@ com_extensions += [
+                         %(shell)s/PyITransferSource.cpp
+                         %(shell)s/PyIUniformResourceLocator.cpp
+                         %(shell)s/shell.cpp
+-
+-                        """ % dirs).split()),
++                        """ + ("%(shell)s/initguid.cpp" if build_mingw32 else
++                               "%(shell)s/PyIEmptyVolumeCache.cpp %(shell)s/PyIEmptyVolumeCacheCallBack.cpp"))
++                             % dirs).split()),
+ 
+     WinExt_win32com('propsys', libraries='propsys', delay_load_libraries='shell32',
+                     unicode_mode=True,
+@@ -2031,9 +2160,8 @@ com_extensions += [
+                     implib_name="pypropsys",
+                     ),
+ 
+-
+-    WinExt_win32com('taskscheduler', libraries='mstask',
+-                    sources=("""
++    WinExt_win32com('taskscheduler', libraries='mstask' + (' pythoncom pywintypes'  if build_mingw32 else ''),
++                    sources=(("""
+                         %(taskscheduler)s/taskscheduler.cpp
+                         %(taskscheduler)s/PyIProvideTaskPage.cpp
+                         %(taskscheduler)s/PyIScheduledWorkItem.cpp
+@@ -2041,7 +2169,7 @@ com_extensions += [
+                         %(taskscheduler)s/PyITaskScheduler.cpp
+                         %(taskscheduler)s/PyITaskTrigger.cpp
+ 
+-                        """ % dirs).split()),
++                        """ + ("%(taskscheduler)s/initguid.cpp" if build_mingw32 else ""))% dirs).split()),
+     WinExt_win32com('bits', libraries='Bits', pch_header="bits_pch.h",
+                     sources=("""
+                         %(bits)s/bits.cpp
+@@ -2077,12 +2205,12 @@ com_extensions += [
+                         %(directsound)s/PyIDirectSoundCaptureBuffer.h %(directsound)s/PyIDirectSoundNotify.h
+                         """ % dirs).split(),
+                     optional_headers = ['dsound.h'],
+-                    libraries='user32 dsound dxguid'),
+-    WinExt_win32com('authorization', libraries='aclui advapi32',
++                    libraries=('pythoncom pywintypes ' if build_mingw32 else '') + 'user32 dsound dxguid uuid'),
++    WinExt_win32com('authorization', libraries=('pythoncom pywintypes ' if build_mingw32 else '') + 'aclui advapi32',
+                     sources=("""
+                         %(authorization)s/authorization.cpp
+                         %(authorization)s/PyGSecurityInformation.cpp
+-                        """ % dirs).split()),
++                        """ % dirs).split())
+ ]
+ 
+ pythonwin_extensions = [
+@@ -2253,20 +2381,24 @@ other_extensions.append(
+ W32_exe_files = [
+     WinExt_win32("pythonservice",
+          sources=[os.path.join("win32", "src", s) for s in
+-                  "PythonService.cpp PythonService.rc".split()],
++                  (("PythonServiceMessages.mc " if build_mingw32 else "") + "PythonService.cpp PythonService.rc").split()],
+          unicode_mode = True,
+-         extra_link_args=["/SUBSYSTEM:CONSOLE"],
+-         libraries = "user32 advapi32 ole32 shell32"),
+-    WinExt_pythonwin("Pythonwin",
+-        sources = [
+-            "Pythonwin/pythonwin.cpp",
+-            "Pythonwin/pythonwin.rc",
+-            "Pythonwin/stdafxpw.cpp",
+-            ],
+-        extra_link_args=["/SUBSYSTEM:WINDOWS"],
+-        optional_headers=['afxres.h']),
++         extra_link_args=[] if build_mingw32 else ["/SUBSYSTEM:CONSOLE"],
++         libraries = ("pywintypes " if build_mingw32 else "") + "user32 advapi32 ole32 shell32")
+ ]
+ 
++if not build_mingw32:
++    W32_exe_files.append(
++        WinExt_pythonwin("Pythonwin",
++            sources = [
++                "Pythonwin/pythonwin.cpp",
++                "Pythonwin/pythonwin.rc",
++                "Pythonwin/stdafxpw.cpp",
++            ],
++            extra_link_args=["/SUBSYSTEM:WINDOWS"],
++            optional_headers=['afxres.h'])
++        )
++
+ # Special definitions for SWIG.
+ swig_interface_parents = {
+     # source file base,     "base class" for generated COM support
+@@ -2415,7 +2547,10 @@ packages=['win32com',
+           ]
+ 
+ py_modules = expand_modules("win32\\lib")
+-ext_modules = win32_extensions + com_extensions + pythonwin_extensions + \
++if build_mingw32:
++    ext_modules = win32_extensions + com_extensions + other_extensions
++else:
++    ext_modules = win32_extensions + com_extensions + pythonwin_extensions + \
+                     other_extensions
+ 
+ # Build a map of DLL base addresses.  According to Python's PC\dllbase_nt.txt,
+diff --git a/win32/src/PerfMon/perfmondata.cpp b/win32/src/PerfMon/perfmondata.cpp
+index 23e7557..c456d89 100644
+--- a/win32/src/PerfMon/perfmondata.cpp
++++ b/win32/src/PerfMon/perfmondata.cpp
+@@ -89,10 +89,19 @@ PPERF_COUNTER_BLOCK pCounterBlock;
+ //      these are used to insure that the data collection functions
+ //      accessed by Perflib will have the correct calling format.
+ //
++
++#if defined(__MINGW32__)
++extern "C" {
++#endif
++
+ PM_OPEN_PROC   OpenPerformanceData;
+ PM_COLLECT_PROC    CollectPerformanceData;
+ PM_CLOSE_PROC  ClosePerformanceData;
+ 
++#if defined(__MINGW32__)
++}
++#endif
++
+ TCHAR szFullModulePath[MAX_PATH];
+ TCHAR szModuleName[MAX_PATH]; // will point into the buffer above.
+ 
+@@ -130,6 +139,9 @@ BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+ 
+ 
+ 
++#if defined(__MINGW32__)
++extern "C"
++#endif
+ DWORD APIENTRY OpenPerformanceData( LPWSTR lpDeviceNames )
+ /*++
+     Routine Description:
+@@ -278,6 +290,9 @@ OpenExitPoint:
+ 	return status;
+ }
+ 
++#if defined(__MINGW32__)
++extern "C"
++#endif
+ DWORD APIENTRY CollectPerformanceData(
+     IN      LPWSTR  lpValueName,
+ 	IN OUT  LPVOID  *lppData,
+@@ -379,6 +394,9 @@ Arguments:   IN       LPWSTR   lpValueName
+     return ERROR_SUCCESS;
+ }
+ 
++#if defined(__MINGW32__)
++extern "C"
++#endif
+ DWORD APIENTRY ClosePerformanceData()
+ /*++
+ Routine Description:
+@@ -445,7 +463,11 @@ HANDLE MonOpenEventLog (const TCHAR *szSourceName)
+ --*/
+ {
+     HKEY hAppKey;
++#if defined(__MINGW32__)
++    TCHAR LogLevelKeyName[] = _T("SOFTWARE\\Microsoft\\Windows_NT\\CurrentVersion\\Perflib");
++#else
+     TCHAR LogLevelKeyName[] = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib");
++#endif
+ 
+     TCHAR LogLevelValueName[] = _T("EventLogLevel");
+ 	LONG lStatus;
+diff --git a/win32/src/PySECURITY_DESCRIPTOR.cpp b/win32/src/PySECURITY_DESCRIPTOR.cpp
+index 218daf9..2873603 100644
+--- a/win32/src/PySECURITY_DESCRIPTOR.cpp
++++ b/win32/src/PySECURITY_DESCRIPTOR.cpp
+@@ -6,6 +6,10 @@
+ #include "PySecurityObjects.h"
+ #include "structmember.h"
+ 
++#if defined(__MINGW32__)
++#include <algorithm>
++#endif
++
+ #ifndef NO_PYWINTYPES_SECURITY
+ BOOL (WINAPI *setsecuritydescriptorcontrol)(PSECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL, SECURITY_DESCRIPTOR_CONTROL)=NULL;
+ 
+@@ -786,7 +790,11 @@ PySECURITY_DESCRIPTOR::PySECURITY_DESCRIPTOR(Py_ssize_t cb /*= 0*/)
+ {
+ 	ob_type = &PySECURITY_DESCRIPTORType;
+ 	_Py_NewReference(this);
++#if defined(__MINGW32__)
++	cb = std::max(cb, static_cast<Py_ssize_t>(SECURITY_DESCRIPTOR_MIN_LENGTH));
++#else
+ 	cb = max(cb, SECURITY_DESCRIPTOR_MIN_LENGTH);
++#endif
+ 	PSECURITY_DESCRIPTOR psd = malloc(cb);
+ 	this->m_psd=NULL;
+ 	if (::InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION))
+diff --git a/win32/src/PyWinTypes.h b/win32/src/PyWinTypes.h
+index 00ac8a1..a5fc23e 100644
+--- a/win32/src/PyWinTypes.h
++++ b/win32/src/PyWinTypes.h
+@@ -393,8 +393,13 @@ PYWINTYPES_EXPORT PyObject *PyWinObject_FromULARGE_INTEGER(ULARGE_INTEGER &val);
+ // We also happen to know a LARGE_INTEGER is an __int64, so do it the easy way
+ #define PyWinObject_AsPY_LONG_LONG(ob, pResult) PyWinObject_AsLARGE_INTEGER((ob), (LARGE_INTEGER *)(pResult))
+ #define PyWinObject_AsUPY_LONG_LONG(ob, pResult) PyWinObject_AsULARGE_INTEGER((ob), (ULARGE_INTEGER *)(pResult))
++#if defined(__MINGW32__)
++#define PyWinObject_FromPY_LONG_LONG(val) PyWinObject_FromLARGE_INTEGER(val)
++#define PyWinObject_FromUPY_LONG_LONG(val) PyWinObject_FromULARGE_INTEGER(val)
++#else
+ #define PyWinObject_FromPY_LONG_LONG(val) PyWinObject_FromLARGE_INTEGER((LARGE_INTEGER)val)
+ #define PyWinObject_FromUPY_LONG_LONG(val) PyWinObject_FromULARGE_INTEGER((ULARGE_INTEGER)val)
++#endif
+ 
+ // A DWORD_PTR and ULONG_PTR appear to mean "integer long enough to hold a pointer"
+ // It is *not* actually a pointer (but is the same size as a pointer)
+@@ -797,7 +802,7 @@ private:
+ 
+ // A helper for simple exception handling.
+ // try/__try
+-#ifdef MAINWIN
++#if defined(__MINGW32__) || defined(MAINWIN)
+ #define PYWINTYPES_TRY try
+ #else
+ #define PYWINTYPES_TRY __try
+diff --git a/win32/src/PyWinTypesmodule.cpp b/win32/src/PyWinTypesmodule.cpp
+index e136fff..77e10a4 100644
+--- a/win32/src/PyWinTypesmodule.cpp
++++ b/win32/src/PyWinTypesmodule.cpp
+@@ -1140,7 +1140,11 @@ BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
+ }
+ 
+ // Function to format a python traceback into a character string.
++#if defined(__MINGW32__)
++#define GPEM_ERROR(what) {errorMsg = "<Error getting traceback - " what ">";goto done;}
++#else
+ #define GPEM_ERROR(what) {errorMsg = "<Error getting traceback - " ## what ## ">";goto done;}
++#endif
+ char *GetPythonTraceback(PyObject *exc_type, PyObject *exc_value, PyObject *exc_tb)
+ {
+ 	// Sleep (30000); // Time enough to attach the debugger (barely)
+diff --git a/win32/src/PythonService.cpp b/win32/src/PythonService.cpp
+index c7b7531..8a9121d 100644
+--- a/win32/src/PythonService.cpp
++++ b/win32/src/PythonService.cpp
+@@ -302,7 +302,11 @@ static PyObject *PySetEventSourceName(PyObject *self, PyObject *args)
+ 	if (!PyWinObject_AsTCHAR(obName, &msg))
+ 		return NULL;
+ 	_tcsncpy(g_szEventSourceName, msg,
++#if defined(__MINGW32__)
++			 sizeof(g_szEventSourceName)/sizeof(TCHAR));
++#else
+ 			 sizeof g_szEventSourceName/sizeof TCHAR);
++#endif
+ 	PyWinObject_FreeTCHAR(msg);
+ 	g_bRegisteredEventSource = FALSE; // so this name re-registered.
+ 	if (registerNow)
+@@ -680,10 +684,18 @@ BOOL PythonService_Initialize( const TCHAR *evtsrc_name, const TCHAR *evtsrc_fil
+ {
+ 	if (evtsrc_name && *evtsrc_name)
+ 		_tcsncpy(g_szEventSourceName, evtsrc_name,
++#if defined(__MINGW32__)
++				 sizeof(g_szEventSourceName)/sizeof(TCHAR));
++#else
+ 				 sizeof g_szEventSourceName/sizeof TCHAR);
++#endif
+ 	if (evtsrc_file && *evtsrc_file)
+ 		_tcsncpy(g_szEventSourceFileName, evtsrc_file,
++#if defined(__MINGW32__)
++				 sizeof(g_szEventSourceFileName)/sizeof(TCHAR));
++#else
+ 				 sizeof g_szEventSourceFileName/sizeof TCHAR);
++#endif
+ 	return TRUE;
+ }
+ 
+@@ -1443,7 +1455,11 @@ static void CheckRegisterEventSourceFile()
+ 
+ 	if (!g_szEventSourceFileName[0])
+ 		GetModuleFileName(g_hdll, g_szEventSourceFileName,
++#if defined(__MINGW32__)
++		                  sizeof(g_szEventSourceFileName)/sizeof(TCHAR));
++#else
+ 		                  sizeof g_szEventSourceFileName/sizeof TCHAR);
++#endif
+ 
+ 	HKEY hkey;
+ 	TCHAR keyName[MAX_PATH];
+@@ -1549,7 +1565,11 @@ BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+ #else // PYSERVICE_BUILD_DLL
+ // Our EXE entry point.
+ 
++#if defined(__MINGW32__)
++extern "C" int main(int argc, TCHAR **argv)
++#else
+ int _tmain(int argc, TCHAR **argv)
++#endif
+ {
+ 	PyObject *module, *f;
+ 	PyThreadState *threadState;
+diff --git a/win32/src/PythonServiceMessages.mc b/win32/src/PythonServiceMessages.mc
+index ef26675..c8787a4 100644
+--- a/win32/src/PythonServiceMessages.mc
++++ b/win32/src/PythonServiceMessages.mc
+@@ -134,6 +134,7 @@ MessageId=0x7
+ Severity=Error
+ SymbolicName=E_UNUSED2
+ Language=English
++%1
+ .
+ 
+ MessageId=0x8
+diff --git a/win32/src/odbc.cpp b/win32/src/odbc.cpp
+index c58aef5..9d3dc35 100644
+--- a/win32/src/odbc.cpp
++++ b/win32/src/odbc.cpp
+@@ -18,6 +18,10 @@
+ #include "PyWinObjects.h"
+ #include "structmember.h"
+ 
++#if defined(__MINGW32__)
++#include <algorithm>
++#endif
++
+ #include <sql.h>
+ #include <sqlext.h>
+ 
+@@ -105,96 +109,10 @@ static cursorObject *cursor(PyObject *o)
+ }
+ 
+ static void cursorDealloc(PyObject *self);
+-PyMethodDef cursorMethods[];
+-PyMemberDef cursorMembers[];
+ 
+-static PyTypeObject Cursor_Type =
+-{
+-	PYWIN_OBJECT_HEAD
+-	"odbccur",				/*tp_name */
+-	sizeof(cursorObject),	/*tp_basicsize */
+-	0,						/*tp_itemsize */
+-	cursorDealloc,			/*tp_dealloc */
+-	0,						/*tp_print */
+-	0,						/*tp_getattr */
+-	0,						/*tp_setattr */
+-	0,						/*tp_compare */
+-	0,						/*tp_repr */
+-	0,						/*tp_as_number */
+-	0,						/* tp_as_sequence */
+-	0,						/* tp_as_mapping */
+-	0,						/* tp_hash */
+-	0,						/* tp_call */
+-	0,						/*tp_str */
+-	PyObject_GenericGetAttr,	/* tp_getattro dbiGetAttr */
+-	PyObject_GenericSetAttr,	/* tp_setattro */
+-	0,						/*tp_as_buffer*/
+-	Py_TPFLAGS_DEFAULT,		/* tp_flags */
+-	0,						/* tp_doc */
+-	0,						/* tp_traverse */
+-	0,						/* tp_clear */
+-	0,						/* tp_richcompare */
+-	0,						/* tp_weaklistoffset */
+-	0,						/* tp_iter */
+-	0,						/* tp_iternext */
+-	cursorMethods,			/* tp_methods */
+-	cursorMembers,			/* tp_members */
+-	0,						/* tp_getset */
+-	0,						/* tp_base */
+-	0,						/* tp_dict */
+-	0,						/* tp_descr_get */
+-	0,						/* tp_descr_set */
+-	0,						/* tp_dictoffset */
+-	0,						/* tp_init */
+-	0,						/* tp_alloc */
+-	0,						/* tp_new */
+-};
+ 
+ 
+ static void connectionDealloc(PyObject *self);
+-PyMethodDef connectionMethods[];
+-PyMemberDef connectionMembers[];
+-static PyTypeObject Connection_Type =
+-{
+-	PYWIN_OBJECT_HEAD
+-	"odbcconn",				/*tp_name */
+-	sizeof (connectionObject),	/*tp_basicsize */
+-	0,						/*tp_itemsize */
+-	connectionDealloc,		/*tp_dealloc */
+-	0,						/*tp_print */
+-	0,						/*tp_getattr */
+-	0,						/*tp_setattr */
+-	0,						/*tp_compare */
+-	0,						/*tp_repr */
+-	0,						/*tp_as_number */
+-	0,						/* tp_as_sequence */
+-	0,						/* tp_as_mapping */
+-	0,						/* tp_hash */
+-	0,						/* tp_call */
+-	0,						/*tp_str */
+-	PyObject_GenericGetAttr,	/* tp_getattro dbiGetAttr */
+-	PyObject_GenericSetAttr,	/* tp_setattro */
+-	0,						/*tp_as_buffer*/
+-	Py_TPFLAGS_DEFAULT,		/* tp_flags */
+-	0,						/* tp_doc */
+-	0,						/* tp_traverse */
+-	0,						/* tp_clear */
+-	0,						/* tp_richcompare */
+-	0,						/* tp_weaklistoffset */
+-	0,						/* tp_iter */
+-	0,						/* tp_iternext */
+-	connectionMethods,		/* tp_methods */
+-	connectionMembers,		/* tp_members */
+-	0,						/* tp_getset */
+-	0,						/* tp_base */
+-	0,						/* tp_dict */
+-	0,						/* tp_descr_get */
+-	0,						/* tp_descr_set */
+-	0,						/* tp_dictoffset */
+-	0,						/* tp_init */
+-	0,						/* tp_alloc */
+-	0,						/* tp_new */
+-};
+ 
+ static int unsuccessful(RETCODE rc)
+ {
+@@ -334,144 +252,6 @@ static int attemptReconnect(cursorObject *cur)
+ }
+ 
+ 
+-/* @pymethod |connection|setautocommit|Sets the autocommit mode. */
+-static PyObject *odbcSetAutoCommit(PyObject *self, PyObject *args)
+-{
+-	int c;
+-	connectionObject *conn;
+-	/* @pyparm int|c||The boolean autocommit mode. */
+-	if (!PyArg_ParseTuple(args, "i",&c))
+-		return NULL;
+-	conn=connection(self);
+-	if (c==0)
+-	{
+-		if (unsuccessful(SQLSetConnectOption(
+-			conn->hdbc,
+-			SQL_AUTOCOMMIT,
+-			SQL_AUTOCOMMIT_OFF)))
+-		{
+-			connectionError(conn, _T("SETAUTOCOMMIT"));
+-			return NULL;
+-		}
+-	}
+-	else
+-	{
+-		if (unsuccessful(SQLSetConnectOption(
+-			conn->hdbc,
+-			SQL_AUTOCOMMIT,
+-			SQL_AUTOCOMMIT_ON)))
+-		{
+-			connectionError(conn, _T("SETAUTOCOMMIT"));
+-			return NULL;
+-		};
+-	}
+-
+-	Py_INCREF(Py_None);
+-	return Py_None;
+-}
+-
+-
+-/* @pymethod |connection|commit|Commits a transaction. */
+-static PyObject *odbcCommit(PyObject *self, PyObject *args)
+-{
+-	RETCODE rc;
+-	Py_BEGIN_ALLOW_THREADS
+-	rc = SQLTransact(
+-		Env,
+-		connection(self)->hdbc,
+-		SQL_COMMIT);
+-	Py_END_ALLOW_THREADS
+-	if (unsuccessful(rc))
+-	{
+-		connectionError(connection(self), _T("COMMIT"));
+-		return 0;
+-	}
+-	else
+-	{
+-		Py_INCREF(Py_None);
+-		return Py_None;
+-	}
+-}
+-
+-/* @pymethod |connection|rollback|Rollsback a transaction. */
+-static PyObject *odbcRollback(PyObject *self, PyObject *args)
+-{
+-	RETCODE rc;
+-	Py_BEGIN_ALLOW_THREADS
+-	rc = SQLTransact(
+-		Env,
+-		connection(self)->hdbc,
+-		SQL_ROLLBACK);
+-	Py_END_ALLOW_THREADS
+-	if (unsuccessful(rc))
+-	{
+-		connectionError(connection(self), _T("ROLLBACK"));
+-		return 0;
+-	}
+-	else {
+-		Py_INCREF(Py_None);
+-		return Py_None;
+-	}
+-}
+-
+-/* @pymethod |connection|cursor|Creates a <o cursor> object */
+-static PyObject *odbcCursor(PyObject *self, PyObject *args)
+-{
+-	connectionObject *conn = connection(self);
+-	if (conn->connected == 0)
+-	{
+-		if (doConnect(conn))
+-		{
+-			return 0;
+-		}
+-	}
+-
+-	cursorObject *cur = PyObject_New(cursorObject, &Cursor_Type);
+-	if (cur == NULL)
+-		return NULL;
+-
+-	cur->outputVars = 0;
+-	cur->inputVars = 0;
+-	cur->description = 0;
+-	cur->max_width = 65536L;
+-	cur->my_conx = 0;
+-	cur->hstmt=NULL;
+-	cur->cursorError=odbcError;
+-	Py_INCREF(odbcError);
+-	if (unsuccessful(SQLAllocStmt(conn->hdbc, &cur->hstmt)))
+-	{
+-		connectionError(cur->my_conx, _T("OPEN"));
+-		Py_DECREF(cur);
+-		return NULL;
+-	}
+-	cur->my_conx = conn;
+-	cur->connect_id = cur->my_conx->connect_id;
+-	Py_INCREF(self); /* the cursors owns a reference to the connection */
+-	return (PyObject*) cur;
+-}
+-
+-/* @pymethod |connection|close|Closes the connection. */
+-static PyObject *odbcClose(PyObject *self, PyObject *args)
+-{
+-  Py_INCREF(Py_None);
+-  return Py_None;
+-}
+-
+-/* @object connection|An object representing an ODBC connection */
+-static struct PyMethodDef connectionMethods[] = {
+-	{ "setautocommit", odbcSetAutoCommit, 1 }, /* @pymeth setautocommit|Sets the autocommit mode. */
+-	{ "commit", odbcCommit, 1 } , /* @pymeth commit|Commits a transaction. */
+-	{ "rollback", odbcRollback, 1 } , /* @pymeth rollback|Rollsback a transaction. */
+-	{ "cursor", odbcCursor, 1 } , /* @pymeth cursor|Creates a <o cursor> object */
+-	{ "close", odbcClose, 1 } , /* @pymeth close|Closes the connection. */
+-	{0,     0}
+-};
+-
+-static PyMemberDef connectionMembers[] = {
+-	{"error", T_OBJECT, offsetof(connectionObject, connectionError), READONLY},
+-	{NULL}
+-};
+-
+ static void connectionDealloc(PyObject *self)
+ {
+ 	Py_XDECREF(connection(self)->connectionError);
+@@ -1192,21 +972,41 @@ static int display_size(short coltype, int collen, const TCHAR *colname)
+     case SQL_DATE:
+     case SQL_TIMESTAMP:
+     case SQL_BIT:
++#if defined(__MINGW32__)
++      return(std::max(collen, (int)_tcslen(colname)));
++#else
+       return(max(collen, (int)_tcslen(colname)));
++#endif
+     case SQL_SMALLINT:
+     case SQL_INTEGER:
+     case SQL_TINYINT:
++#if defined(__MINGW32__)
++      return(std::max(collen+1, (int)_tcslen(colname)));
++#else
+       return(max(collen+1, (int)_tcslen(colname)));
++#endif
+     case SQL_DECIMAL:
+     case SQL_NUMERIC:
++#if defined(__MINGW32__)
++      return(std::max(collen+2, (int)_tcslen(colname)));
++#else
+       return(max(collen+2, (int)_tcslen(colname)));
++#endif
+     case SQL_REAL:
+     case SQL_FLOAT:
+     case SQL_DOUBLE:
++#if defined(__MINGW32__)
++      return(std::max(20, (int)_tcslen(colname)));
++#else
+       return(max(20, (int)_tcslen(colname)));
++#endif
+     case SQL_BINARY:
+     case SQL_VARBINARY:
++#if defined(__MINGW32__)
++      return(std::max(2*collen, (int)_tcslen(colname)));
++#else
+       return(max(2*collen, (int)_tcslen(colname)));
++#endif
+     case SQL_LONGVARBINARY:
+     case SQL_LONGVARCHAR:
+     default:
+@@ -1814,6 +1614,226 @@ static PyMemberDef cursorMembers[] = {
+ 	{NULL}
+ };
+ 
++static PyTypeObject Cursor_Type =
++{
++	PYWIN_OBJECT_HEAD
++	"odbccur",				/*tp_name */
++	sizeof(cursorObject),	/*tp_basicsize */
++	0,						/*tp_itemsize */
++	cursorDealloc,			/*tp_dealloc */
++	0,						/*tp_print */
++	0,						/*tp_getattr */
++	0,						/*tp_setattr */
++	0,						/*tp_compare */
++	0,						/*tp_repr */
++	0,						/*tp_as_number */
++	0,						/* tp_as_sequence */
++	0,						/* tp_as_mapping */
++	0,						/* tp_hash */
++	0,						/* tp_call */
++	0,						/*tp_str */
++	PyObject_GenericGetAttr,	/* tp_getattro dbiGetAttr */
++	PyObject_GenericSetAttr,	/* tp_setattro */
++	0,						/*tp_as_buffer*/
++	Py_TPFLAGS_DEFAULT,		/* tp_flags */
++	0,						/* tp_doc */
++	0,						/* tp_traverse */
++	0,						/* tp_clear */
++	0,						/* tp_richcompare */
++	0,						/* tp_weaklistoffset */
++	0,						/* tp_iter */
++	0,						/* tp_iternext */
++	cursorMethods,			/* tp_methods */
++	cursorMembers,			/* tp_members */
++	0,						/* tp_getset */
++	0,						/* tp_base */
++	0,						/* tp_dict */
++	0,						/* tp_descr_get */
++	0,						/* tp_descr_set */
++	0,						/* tp_dictoffset */
++	0,						/* tp_init */
++	0,						/* tp_alloc */
++	0,						/* tp_new */
++};
++/* @pymethod |connection|setautocommit|Sets the autocommit mode. */
++static PyObject *odbcSetAutoCommit(PyObject *self, PyObject *args)
++{
++	int c;
++	connectionObject *conn;
++	/* @pyparm int|c||The boolean autocommit mode. */
++	if (!PyArg_ParseTuple(args, "i",&c))
++		return NULL;
++	conn=connection(self);
++	if (c==0)
++	{
++		if (unsuccessful(SQLSetConnectOption(
++			conn->hdbc,
++			SQL_AUTOCOMMIT,
++			SQL_AUTOCOMMIT_OFF)))
++		{
++			connectionError(conn, _T("SETAUTOCOMMIT"));
++			return NULL;
++		}
++	}
++	else
++	{
++		if (unsuccessful(SQLSetConnectOption(
++			conn->hdbc,
++			SQL_AUTOCOMMIT,
++			SQL_AUTOCOMMIT_ON)))
++		{
++			connectionError(conn, _T("SETAUTOCOMMIT"));
++			return NULL;
++		};
++	}
++
++	Py_INCREF(Py_None);
++	return Py_None;
++}
++
++
++/* @pymethod |connection|commit|Commits a transaction. */
++static PyObject *odbcCommit(PyObject *self, PyObject *args)
++{
++	RETCODE rc;
++	Py_BEGIN_ALLOW_THREADS
++	rc = SQLTransact(
++		Env,
++		connection(self)->hdbc,
++		SQL_COMMIT);
++	Py_END_ALLOW_THREADS
++	if (unsuccessful(rc))
++	{
++		connectionError(connection(self), _T("COMMIT"));
++		return 0;
++	}
++	else
++	{
++		Py_INCREF(Py_None);
++		return Py_None;
++	}
++}
++
++/* @pymethod |connection|rollback|Rollsback a transaction. */
++static PyObject *odbcRollback(PyObject *self, PyObject *args)
++{
++	RETCODE rc;
++	Py_BEGIN_ALLOW_THREADS
++	rc = SQLTransact(
++		Env,
++		connection(self)->hdbc,
++		SQL_ROLLBACK);
++	Py_END_ALLOW_THREADS
++	if (unsuccessful(rc))
++	{
++		connectionError(connection(self), _T("ROLLBACK"));
++		return 0;
++	}
++	else {
++		Py_INCREF(Py_None);
++		return Py_None;
++	}
++}
++
++/* @pymethod |connection|cursor|Creates a <o cursor> object */
++static PyObject *odbcCursor(PyObject *self, PyObject *args)
++{
++	connectionObject *conn = connection(self);
++	if (conn->connected == 0)
++	{
++		if (doConnect(conn))
++		{
++			return 0;
++		}
++	}
++
++	cursorObject *cur = PyObject_New(cursorObject, &Cursor_Type);
++	if (cur == NULL)
++		return NULL;
++
++	cur->outputVars = 0;
++	cur->inputVars = 0;
++	cur->description = 0;
++	cur->max_width = 65536L;
++	cur->my_conx = 0;
++	cur->hstmt=NULL;
++	cur->cursorError=odbcError;
++	Py_INCREF(odbcError);
++	if (unsuccessful(SQLAllocStmt(conn->hdbc, &cur->hstmt)))
++	{
++		connectionError(cur->my_conx, _T("OPEN"));
++		Py_DECREF(cur);
++		return NULL;
++	}
++	cur->my_conx = conn;
++	cur->connect_id = cur->my_conx->connect_id;
++	Py_INCREF(self); /* the cursors owns a reference to the connection */
++	return (PyObject*) cur;
++}
++
++/* @pymethod |connection|close|Closes the connection. */
++static PyObject *odbcClose(PyObject *self, PyObject *args)
++{
++  Py_INCREF(Py_None);
++  return Py_None;
++}
++
++/* @object connection|An object representing an ODBC connection */
++static struct PyMethodDef connectionMethods[6] = {
++	{ "setautocommit", odbcSetAutoCommit, 1 }, /* @pymeth setautocommit|Sets the autocommit mode. */
++	{ "commit", odbcCommit, 1 } , /* @pymeth commit|Commits a transaction. */
++	{ "rollback", odbcRollback, 1 } , /* @pymeth rollback|Rollsback a transaction. */
++	{ "cursor", odbcCursor, 1 } , /* @pymeth cursor|Creates a <o cursor> object */
++	{ "close", odbcClose, 1 } , /* @pymeth close|Closes the connection. */
++	{0,     0}
++};
++
++static PyMemberDef connectionMembers[2] = {
++	{"error", T_OBJECT, offsetof(connectionObject, connectionError), READONLY},
++	{NULL}
++};
++
++static PyTypeObject Connection_Type =
++{
++	PYWIN_OBJECT_HEAD
++	"odbcconn",				/*tp_name */
++	sizeof (connectionObject),	/*tp_basicsize */
++	0,						/*tp_itemsize */
++	connectionDealloc,		/*tp_dealloc */
++	0,						/*tp_print */
++	0,						/*tp_getattr */
++	0,						/*tp_setattr */
++	0,						/*tp_compare */
++	0,						/*tp_repr */
++	0,						/*tp_as_number */
++	0,						/* tp_as_sequence */
++	0,						/* tp_as_mapping */
++	0,						/* tp_hash */
++	0,						/* tp_call */
++	0,						/*tp_str */
++	PyObject_GenericGetAttr,	/* tp_getattro dbiGetAttr */
++	PyObject_GenericSetAttr,	/* tp_setattro */
++	0,						/*tp_as_buffer*/
++	Py_TPFLAGS_DEFAULT,		/* tp_flags */
++	0,						/* tp_doc */
++	0,						/* tp_traverse */
++	0,						/* tp_clear */
++	0,						/* tp_richcompare */
++	0,						/* tp_weaklistoffset */
++	0,						/* tp_iter */
++	0,						/* tp_iternext */
++	connectionMethods,		/* tp_methods */
++	connectionMembers,		/* tp_members */
++	0,						/* tp_getset */
++	0,						/* tp_base */
++	0,						/* tp_dict */
++	0,						/* tp_descr_get */
++	0,						/* tp_descr_set */
++	0,						/* tp_dictoffset */
++	0,						/* tp_init */
++	0,						/* tp_alloc */
++	0,						/* tp_new */
++};
+ static void parseInfo(connectionObject *conn, const TCHAR *c)
+ {
+ 	TCHAR *p;
+diff --git a/win32/src/win32apimodule.cpp b/win32/src/win32apimodule.cpp
+index f7e36b1..dd5223f 100644
+--- a/win32/src/win32apimodule.cpp
++++ b/win32/src/win32apimodule.cpp
+@@ -817,12 +817,16 @@ PyFormatMessageA(PyObject *self, PyObject *args)
+ 	
+ 	{
+ 	PyW32_BEGIN_ALLOW_THREADS
++#if !defined(__MINGW32__)
+ 	__try{
++#endif
+ 		lrc = ::FormatMessageA(flags, pSource, msgId, langId, (LPSTR)&resultBuf, 0, (va_list *)pInserts );
++#if !defined(__MINGW32__)
+ 		}
+ 	__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH){
+ 		baccessviolation=TRUE;
+ 		}
++#endif
+ 	PyW32_END_ALLOW_THREADS
+ 	}
+ 
+@@ -927,12 +931,16 @@ PyFormatMessageW(PyObject *self, PyObject *args)
+ 
+ 	{
+ 	PyW32_BEGIN_ALLOW_THREADS
++#if !defined(__MINGW32__)
+ 	__try{
++#endif
+ 		lrc = ::FormatMessageW(flags, pSource, msgId, langId, (LPWSTR)&resultBuf, 0, (va_list *)pInserts );
++#if !defined(__MINGW32__)
+ 		}
+ 	__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH){
+ 		baccessviolation=TRUE;
+ 		}
++#endif 
+ 	PyW32_END_ALLOW_THREADS
+ 	}
+ 
+@@ -5774,8 +5782,11 @@ static PyObject *PyApply(PyObject *self, PyObject *args)
+ 	}
+ 	PyThreadState *stateSave = PyThreadState_Swap(NULL);
+ 	PyThreadState_Swap(stateSave);
++#if !defined(__MINGW32__)
+ 	_try {
++#endif
+ 		ret = PyObject_CallObject(obFunc, obArgs);
++#if !defined(__MINGW32__)
+ 	}
+ 	_except( PyApplyExceptionFilter( GetExceptionCode(),
+ 	                                 GetExceptionInformation(),
+@@ -5804,6 +5815,7 @@ static PyObject *PyApply(PyObject *self, PyObject *args)
+ 		Py_XDECREF(exc_value);
+ 		ret = NULL;
+ 	}
++#endif
+ 	return ret;
+ // @comm Calls the specified function in a manner similar to 
+ // the built-in function apply(), but allows Win32 exceptions
+diff --git a/win32/src/win32crypt/PyCRYPTPROV.cpp b/win32/src/win32crypt/PyCRYPTPROV.cpp
+index 140ddd3..3de895c 100644
+--- a/win32/src/win32crypt/PyCRYPTPROV.cpp
++++ b/win32/src/win32crypt/PyCRYPTPROV.cpp
+@@ -1,6 +1,10 @@
+ // @doc
+ #include "win32crypt.h"
+ 
++#if defined(__MINGW32__)
++#include <algorithm>
++#endif
++
+ // @object PyCRYPTPROV|Handle to a cryptographic provider, created using <om cryptoapi.CryptAcquireContext>
+ struct PyMethodDef PyCRYPTPROV::methods[] = {
+ 	// @pymeth CryptReleaseContext|Releases the CSP handle
+@@ -351,7 +355,11 @@ PyObject *PyCRYPTPROV::PyCryptGenRandom(PyObject *self, PyObject *args, PyObject
+ 	//initialize buffer with char string if passed if
+ 	ZeroMemory(pbBuffer, dwLen+1);
+ 	if (seeddata != NULL)
++#if defined(__MINGW32__)
++		memcpy(pbBuffer, seeddata, std::min(dwLen,seedlen));
++#else
+ 		memcpy(pbBuffer, seeddata, min(dwLen,seedlen));
++#endif
+ 	if (CryptGenRandom(hcryptprov, dwLen, pbBuffer))
+ 		ret=PyString_FromStringAndSize((char *)pbBuffer, dwLen);
+ 	else
+diff --git a/win32/src/win32crypt/win32cryptmodule.cpp b/win32/src/win32crypt/win32cryptmodule.cpp
+index 29b2c80..5875294 100644
+--- a/win32/src/win32crypt/win32cryptmodule.cpp
++++ b/win32/src/win32crypt/win32cryptmodule.cpp
+@@ -597,34 +597,59 @@ static PyObject *PyCertOpenStore(PyObject *self, PyObject *args, PyObject *kwarg
+ 		}
+ 	else{
+ 		switch((ULONG_PTR)StoreProvider){
++#if defined(__MINGW32__)
++			case (ULONG_PTR)14:
++			case (ULONG_PTR)8:
++			case (ULONG_PTR)10:
++			case (ULONG_PTR)13:
++			case (ULONG_PTR)16:{
++#else
+ 			case CERT_STORE_PROV_PHYSICAL:
+ 			case CERT_STORE_PROV_FILENAME:
+ 			case CERT_STORE_PROV_SYSTEM:
+ 			case CERT_STORE_PROV_SYSTEM_REGISTRY:
+ 			case CERT_STORE_PROV_LDAP:{
++#endif
+ 				if (!PyWinObject_AsWCHAR(obpvPara, (WCHAR **)&pvPara))
+ 					return NULL;
+ 				free_wchar=TRUE;
+ 				break;
+ 				}
++#if defined(__MINGW32__)
++			case (ULONG_PTR)4:{
++#else
+ 			case CERT_STORE_PROV_REG:{
++#endif
+ 				if (!PyWinObject_AsHKEY(obpvPara, (HKEY *)&pvPara))
+ 					return NULL;
+ 				break;
+ 				}
++#if defined(__MINGW32__)
++			case (ULONG_PTR)3:{
++#else
+ 			case CERT_STORE_PROV_FILE:{
++#endif
+ 				if (!PyWinObject_AsHANDLE(obpvPara, (HANDLE *)&pvPara))
+ 					return NULL;
+ 				break;
+ 				}
++#if defined(__MINGW32__)
++			case (ULONG_PTR)6:
++			case (ULONG_PTR)5:{
++#else
+ 			case CERT_STORE_PROV_SERIALIZED:
+ 			case CERT_STORE_PROV_PKCS7:{
++#endif
+ 				if (!PyWinObject_AsReadBuffer(obpvPara, (void **)&crypt_data_blob.pbData, &crypt_data_blob.cbData))
+ 					return NULL;
+ 				pvPara=(void *)&crypt_data_blob;
+ 				break;
+ 				}
++#if defined(__MINGW32__)
++			case (ULONG_PTR)2:{
++#else
+ 			case CERT_STORE_PROV_MEMORY:{
++#endif
+ 				// pvPara is not used, warn if something passed in
+ 				if (obpvPara != Py_None)
+ 					PyErr_Warn(PyExc_RuntimeWarning, "Para ignored for CERT_STORE_PROV_MEMORY");
+diff --git a/win32/src/win32evtlog.i b/win32/src/win32evtlog.i
+index 847230c..142923b 100644
+--- a/win32/src/win32evtlog.i
++++ b/win32/src/win32evtlog.i
+@@ -1012,11 +1012,15 @@ PyCFunction pfnPyEvtUpdateBookmark = (PyCFunction) PyEvtUpdateBookmark;
+ 
+ PyObject *PyWinObject_FromEVT_VARIANT(PEVT_VARIANT val)
+ {
++#if defined(__MINGW32__)
++	DWORD val_type = val->Type;
++#else
+ 	if (val->Type & EVT_VARIANT_TYPE_ARRAY){
+ 		PyErr_SetString(PyExc_NotImplementedError, "EVT_VARIANT arrays not supported yet");
+ 		return NULL;
+ 		}
+ 	DWORD val_type = val->Type & EVT_VARIANT_TYPE_MASK;
++#endif
+ 	PyObject *obval = NULL;
+ 	switch (val_type){
+ 		case EvtVarTypeNull:
+diff --git a/win32/src/win32file.i b/win32/src/win32file.i
+index 2b82d37..39e7cd1 100644
+--- a/win32/src/win32file.i
++++ b/win32/src/win32file.i
+@@ -1420,11 +1420,19 @@ static PyObject *PyObject_FromFILE_NOTIFY_INFORMATION(void *buffer, DWORD nbytes
+ 	// the filename is exactly 1 byte!  Not clear the best way to
+ 	// check this, but this works for now - is it at least the size of
+ 	// the *head* of the struct.
++#if defined(__MINGW32__)
++	if (nbytes < sizeof(DWORD)*3+2)
++#else
+ 	if (nbytes < sizeof DWORD*3+2)
++#endif
+ 		return ret;
+ 	DWORD nbytes_read = 0;
+ 	while (1) {
++#if defined(__MINGW32__)
++                PyObject *fname = PyWinObject_FromOLECHAR(p->FileName, p->FileNameLength/sizeof(WCHAR));
++#else
+ 		PyObject *fname = PyWinObject_FromOLECHAR(p->FileName, p->FileNameLength/sizeof WCHAR);
++#endif
+ 		if (!fname) {
+ 			Py_DECREF(ret);
+ 			return NULL;
+diff --git a/win32/src/win32file_comm.cpp b/win32/src/win32file_comm.cpp
+index 19f2eb7..d16fb76 100644
+--- a/win32/src/win32file_comm.cpp
++++ b/win32/src/win32file_comm.cpp
+@@ -173,11 +173,19 @@ PyDCB::~PyDCB(void)
+ {
+ }
+ 
++#if defined(__MINGW32__)
++#define GET_BITFIELD_ENTRY(bitfield_name) \
++	else if (strcmp(name, #bitfield_name)==0) { \
++		return PyInt_FromLong(pydcb->m_DCB. bitfield_name); \
++	} \
++
++#else
+ #define GET_BITFIELD_ENTRY(bitfield_name) \
+ 	else if (strcmp(name, #bitfield_name)==0) { \
+ 		return PyInt_FromLong(pydcb->m_DCB.##bitfield_name); \
+ 	} \
+ 
++#endif
+ PyObject *PyDCB::getattro(PyObject *self, PyObject *obname)
+ {
+ 	PyDCB *pydcb = (PyDCB *)self;
+@@ -204,7 +212,19 @@ PyObject *PyDCB::getattro(PyObject *self, PyObject *obname)
+ 	return PyObject_GenericGetAttr(self, obname);
+ }
+ 
++#if defined(__MINGW32__)
+ #define SET_BITFIELD_ENTRY(bitfield_name) \
++	else if (strcmp(name, #bitfield_name)==0) { \
++		if (!PyInt_Check(v)) { \
++			PyErr_Format(PyExc_TypeError, szNeedIntAttr, #bitfield_name); \
++			return -1; \
++		} \
++		pydcb->m_DCB. bitfield_name = PyInt_AsLong(v); \
++		return 0; \
++	} \
++
++#else
++#define SET_BITFIELD_ENTRY(bitfield_name)           \
+ 	else if (strcmp(name, #bitfield_name)==0) { \
+ 		if (!PyInt_Check(v)) { \
+ 			PyErr_Format(PyExc_TypeError, szNeedIntAttr, #bitfield_name); \
+@@ -214,6 +234,7 @@ PyObject *PyDCB::getattro(PyObject *self, PyObject *obname)
+ 		return 0; \
+ 	} \
+ 
++#endif
+ int PyDCB::setattro(PyObject *self, PyObject *obname, PyObject *v)
+ {
+ 	PyDCB *pydcb = (PyDCB *)self;
+@@ -367,11 +388,19 @@ PyCOMSTAT::~PyCOMSTAT(void)
+ }
+ 
+ #undef GET_BITFIELD_ENTRY
++#if defined(__MINGW32__)
++#define GET_BITFIELD_ENTRY(bitfield_name) \
++	else if (strcmp(name, #bitfield_name)==0) { \
++		return PyInt_FromLong(pyCOMSTAT->m_COMSTAT. bitfield_name); \
++	} \
++
++#else
+ #define GET_BITFIELD_ENTRY(bitfield_name) \
+ 	else if (strcmp(name, #bitfield_name)==0) { \
+ 		return PyInt_FromLong(pyCOMSTAT->m_COMSTAT.##bitfield_name); \
+ 	} \
+ 
++#endif
+ PyObject *PyCOMSTAT::getattro(PyObject *self, PyObject *obname)
+ {
+ 	PyCOMSTAT *pyCOMSTAT = (PyCOMSTAT *)self;
+@@ -392,6 +421,18 @@ PyObject *PyCOMSTAT::getattro(PyObject *self, PyObject *obname)
+ }
+ 
+ #undef SET_BITFIELD_ENTRY
++#if defined(__MINGW32__)
++#define SET_BITFIELD_ENTRY(bitfield_name) \
++	else if (strcmp(name, #bitfield_name)==0) { \
++		if (!PyInt_Check(v)) { \
++			PyErr_Format(PyExc_TypeError, szNeedIntAttr, #bitfield_name); \
++			return -1; \
++		} \
++		pyCOMSTAT->m_COMSTAT. bitfield_name = PyInt_AsLong(v); \
++		return 0; \
++	} \
++
++#else
+ #define SET_BITFIELD_ENTRY(bitfield_name) \
+ 	else if (strcmp(name, #bitfield_name)==0) { \
+ 		if (!PyInt_Check(v)) { \
+@@ -402,6 +443,7 @@ PyObject *PyCOMSTAT::getattro(PyObject *self, PyObject *obname)
+ 		return 0; \
+ 	} \
+ 
++#endif
+ int PyCOMSTAT::setattro(PyObject *self, PyObject *obname, PyObject *v)
+ {
+ 	PyCOMSTAT *pyCOMSTAT = (PyCOMSTAT *)self;
+diff --git a/win32/src/win32gui.i b/win32/src/win32gui.i
+index 94b738f..bc5e494 100644
+--- a/win32/src/win32gui.i
++++ b/win32/src/win32gui.i
+@@ -34,6 +34,9 @@
+ #include "Dbt.h" // device notification
+ #include "malloc.h"
+ 
++#if defined(__MINGW32__)
++#include <algorithm>
++#endif
+ #ifdef MS_WINCE
+ #include "winbase.h"
+ #define IS_INTRESOURCE(res) (((DWORD)(res) & 0xffff0000) == 0)
+@@ -640,7 +643,11 @@ typedef int UINT;
+ // @object TRACKMOUSEEVENT|A tuple of (dwFlags, hwndTrack, dwHoverTime)
+ %typemap(python,in) TRACKMOUSEEVENT *INPUT(TRACKMOUSEEVENT e){
+ 	PyObject *obhwnd;
++#if defined(__MINGW32__)
++	e.cbSize = sizeof(e);
++#else
+ 	e.cbSize = sizeof e;
++#endif
+ 	if (PyTuple_Check($source)) {
+ 		if (PyArg_ParseTuple($source, "lOl", &e.dwFlags, &obhwnd, &e.dwHoverTime) == 0) {
+ 			return PyErr_Format(PyExc_TypeError, "%s: a TRACKMOUSEEVENT must be a tuple of 3 integers", "$name");
+@@ -1822,7 +1829,11 @@ PyObject *PyFlashWindowEx(PyObject *self, PyObject *args)
+ 	PyObject *ret, *obhwnd;
+ 	BOOL rc;
+ 	FLASHWINFO f;
++#if defined(__MINGW32__)
++	f.cbSize = sizeof(f);
++#else
+ 	f.cbSize = sizeof f;
++#endif
+ 	// @pyparm <o PyHANDLE>|hwnd||Handle to a window
+ 	// @pyparm int|dwFlags||Combination of win32con.FLASHW_* flags
+ 	// @pyparm int|uCount||Nbr of times to flash
+@@ -3802,7 +3813,11 @@ static PyObject *PyExtractIconEx(PyObject *self, PyObject *args)
+     nicons_got = 1;
+ #endif
+     // Asking for 1 always says it got 2!?
++#if defined(__MINGW32__)
++    nicons = std::min(nicons, nicons_got);
++#else
+     nicons = min(nicons, nicons_got);
++#endif
+     objects_large = PyList_New(nicons);
+     if (!objects_large) goto done;
+     objects_small = PyList_New(nicons);
+@@ -4596,29 +4611,49 @@ BOOL GetOpenFileName(OPENFILENAME *INPUT);
+ %typemap (python, in) MENUITEMINFO *INPUT (Py_ssize_t target_size){
+ 	if (0 != PyObject_AsReadBuffer($source, (const void **)&$target, &target_size))
+ 		return NULL;
++#if defined(__MINGW32__)
++	if (sizeof(MENUITEMINFO) != target_size)
++		return PyErr_Format(PyExc_TypeError, "Argument must be a %d-byte string/buffer (got %d bytes)", sizeof(MENUITEMINFO), target_size);
++#else
+ 	if (sizeof MENUITEMINFO != target_size)
+ 		return PyErr_Format(PyExc_TypeError, "Argument must be a %d-byte string/buffer (got %d bytes)", sizeof MENUITEMINFO, target_size);
++#endif
+ }
+ 
+ %typemap (python,in) MENUITEMINFO *BOTH(Py_ssize_t target_size) {
+ 	if (0 != PyObject_AsWriteBuffer($source, (void **)&$target, &target_size))
+ 		return NULL;
++#if defined(__MINGW32__)
++	if (sizeof(MENUITEMINFO) != target_size)
++		return PyErr_Format(PyExc_TypeError, "Argument must be a %d-byte buffer (got %d bytes)", sizeof(MENUITEMINFO), target_size);
++#else
+ 	if (sizeof MENUITEMINFO != target_size)
+ 		return PyErr_Format(PyExc_TypeError, "Argument must be a %d-byte buffer (got %d bytes)", sizeof MENUITEMINFO, target_size);
++#endif
+ }
+ 
+ %typemap (python, in) MENUINFO *INPUT (Py_ssize_t target_size){
+ 	if (0 != PyObject_AsReadBuffer($source, (const void **)&$target, &target_size))
+ 		return NULL;
++#if defined(__MINGW32__)
++	if (sizeof(MENUINFO) != target_size)
++		return PyErr_Format(PyExc_TypeError, "Argument must be a %d-byte string/buffer (got %d bytes)", sizeof(MENUINFO), target_size);
++#else
+ 	if (sizeof MENUINFO != target_size)
+ 		return PyErr_Format(PyExc_TypeError, "Argument must be a %d-byte string/buffer (got %d bytes)", sizeof MENUINFO, target_size);
++#endif
+ }
+ 
+ %typemap (python,in) MENUINFO *BOTH(Py_ssize_t target_size) {
+ 	if (0 != PyObject_AsWriteBuffer($source, (void **)&$target, &target_size))
+ 		return NULL;
++#if defined(__MINGW32__)
++	if (sizeof(MENUINFO) != target_size)
++		return PyErr_Format(PyExc_TypeError, "Argument must be a %d-byte buffer (got %d bytes)", sizeof(MENUINFO), target_size);
++#else
+ 	if (sizeof MENUINFO != target_size)
+ 		return PyErr_Format(PyExc_TypeError, "Argument must be a %d-byte buffer (got %d bytes)", sizeof MENUINFO, target_size);
++#endif
+ }
+ 
+ // @pyswig |InsertMenuItem|Inserts a menu item
+@@ -4750,8 +4785,13 @@ PyObject *PySetMenuInfo(PyObject *self, PyObject *args)
+ 
+ 	if (0 != PyObject_AsReadBuffer(obInfo, (const void **)&pInfo, &cbInfo))
+ 		return NULL;
++#if defined(__MINGW32__)
++	if (sizeof(MENUINFO) != cbInfo)
++		return PyErr_Format(PyExc_TypeError, "Argument must be a %d byte string/buffer (got %d bytes)", sizeof(MENUINFO), cbInfo);
++#else
+ 	if (sizeof MENUINFO != cbInfo)
+ 		return PyErr_Format(PyExc_TypeError, "Argument must be a %d byte string/buffer (got %d bytes)", sizeof MENUINFO, cbInfo);
++#endif
+ 
+ 	Py_BEGIN_ALLOW_THREADS
+ 	result = (*pfnSetMenuInfo)(hmenu, pInfo);
+@@ -4787,8 +4827,13 @@ PyObject *PyGetMenuInfo(PyObject *self, PyObject *args)
+ 
+ 	if (0 != PyObject_AsWriteBuffer(obInfo, (void **)&pInfo, &cbInfo))
+ 		return NULL;
++#if defined(__MINGW32__)
++	if (sizeof(MENUINFO) != cbInfo)
++		return PyErr_Format(PyExc_TypeError, "Argument must be a %d byte buffer (got %d bytes)", sizeof(MENUINFO), cbInfo);
++#else
+ 	if (sizeof MENUINFO != cbInfo)
+ 		return PyErr_Format(PyExc_TypeError, "Argument must be a %d byte buffer (got %d bytes)", sizeof MENUINFO, cbInfo);
++#endif
+ 
+ 	Py_BEGIN_ALLOW_THREADS
+ 	result = (*pfnGetMenuInfo)(hmenu, pInfo);
+@@ -6005,7 +6050,11 @@ PyGetClassName(PyObject *self, PyObject *args)
+ 	if (!PyWinObject_AsHANDLE(obhwnd, (HANDLE *)&hwnd))
+ 		return NULL;
+ 	// dont bother with lock - no callback possible.
++#if defined(__MINGW32__)
++	int nchars = GetClassName(hwnd, buf, sizeof(buf)/sizeof(buf[0]));
++#else
+ 	int nchars = GetClassName(hwnd, buf, sizeof buf/sizeof buf[0]);
++#endif
+ 	if (nchars==0)
+ 		return PyWin_SetAPIError("GetClassName");
+ 	return PyWinObject_FromTCHAR(buf, nchars);
+@@ -6370,7 +6419,11 @@ BOOL PyParse_OPENFILENAMEW_Args(PyObject *args, PyObject *kwargs, OPENFILENAMEW
+ 	// lpstrFile buffer receives full path and possibly multiple file names, allocate extra space
+ 	if (!PyWinObject_AsWCHAR(obFile, &initfile, TRUE, &initfilechars))
+ 		goto done;
++#if defined(__MINGW32__)
++	pofn->nMaxFile=std::max(pofn->nMaxFile, initfilechars+1);
++#else
+ 	pofn->nMaxFile=max(pofn->nMaxFile, initfilechars+1);
++#endif
+ 	bufsize=pofn->nMaxFile*sizeof(WCHAR);
+ 	pofn->lpstrFile=(LPWSTR)malloc(bufsize);
+ 	if (pofn->lpstrFile==NULL){
+@@ -7506,13 +7559,13 @@ PyObject *PyRegisterDeviceNotification(PyObject *self, PyObject *args)
+ 				"structure says it has %d bytes, but %d was provided",
+ 				(int)struct_bytes, (int)nbytes);
+ 	// @pyseeapi RegisterDeviceNotification
+-	HDEVNOTIFY not;
++	HDEVNOTIFY notify;
+ 	Py_BEGIN_ALLOW_THREADS
+-	not = RegisterDeviceNotification(handle, (void *)filter, flags);
++	notify = RegisterDeviceNotification(handle, (void *)filter, flags);
+ 	Py_END_ALLOW_THREADS
+-	if (not == NULL)
++	if (notify == NULL)
+ 		return PyWin_SetAPIError("RegisterDeviceNotification");
+-	return PyWinObject_FromHDEVNOTIFY(not);
++	return PyWinObject_FromHDEVNOTIFY(notify);
+ }
+ %}
+ %native(RegisterDeviceNotification) PyRegisterDeviceNotification;
+diff --git a/win32/src/win32inet.i b/win32/src/win32inet.i
+index 92d7462..16a8912 100644
+--- a/win32/src/win32inet.i
++++ b/win32/src/win32inet.i
+@@ -15,6 +15,9 @@
+ %{
+ #undef PyHANDLE // undef earlier define, so we are back to the class.
+ #include "pywinobjects.h"
++#if defined(__MINGW32__)
++#include <algorithm>
++#endif
+ 
+ void CALLBACK PyHINTERNET_StatusChange(
+ 	HINTERNET hInternet,
+@@ -953,8 +956,10 @@ PyObject *PyInternetQueryOption(PyObject *self, PyObject *args)
+ 		case INTERNET_OPTION_RECEIVE_TIMEOUT:	// @flag INTERNET_OPTION_RECEIVE_TIMEOUT|Int - timeout in millseconds
+ 												// @flag INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT|Int - timeout in millseconds
+ 		case INTERNET_OPTION_CODEPAGE:		// @flag INTERNET_OPTION_CODEPAGE|Int - Codepage of host part of URL
++#if !defined(__MINGW32__)
+ 		case INTERNET_OPTION_CODEPAGE_PATH:	// @flag INTERNET_OPTION_CODEPAGE_PATH|Int - Codepage for URL
+ 		case INTERNET_OPTION_CODEPAGE_EXTRA:	// @flag INTERNET_OPTION_CODEPAGE_EXTRA|Int - Codepage for path part of URL
++#endif
+ 		case INTERNET_OPTION_CONNECT_RETRIES:		// @flag INTERNET_OPTION_CONNECT_RETRIES|Int - Number of time to try to reconnect to host
+ 		case INTERNET_OPTION_CONNECT_TIMEOUT:		// @flag INTERNET_OPTION_CONNECT_TIMEOUT|Int - Connection timeout in milliseconds
+ 		case INTERNET_OPTION_CONNECTED_STATE:		// @flag INTERNET_OPTION_CONNECTED_STATE|Int - Connection state, INTERNET_STATE_*
+@@ -962,7 +967,9 @@ PyObject *PyInternetQueryOption(PyObject *self, PyObject *args)
+ 		case INTERNET_OPTION_ERROR_MASK:		// @flag INTERNET_OPTION_ERROR_MASK|Int, combination of INTERNET_ERROR_MASK_*
+ 		case INTERNET_OPTION_EXTENDED_ERROR:		// @flag INTERNET_OPTION_EXTENDED_ERROR|Int, ERROR_INTERNET_*
+ 		case INTERNET_OPTION_FROM_CACHE_TIMEOUT:		// @flag INTERNET_OPTION_FROM_CACHE_TIMEOUT|Int - Timeout in ms before cached copy is used
++#if !defined(__MINGW32__)
+ 		case INTERNET_OPTION_IDN:		// @flag INTERNET_OPTION_IDN|Int, INTERNET_FLAG_IDN_*
++#endif
+ 		case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:		// @flag INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER|Int
+ 		case INTERNET_OPTION_MAX_CONNS_PER_SERVER:		// @flag INTERNET_OPTION_MAX_CONNS_PER_SERVER|Int
+ 		case INTERNET_OPTION_READ_BUFFER_SIZE:		// @flag INTERNET_OPTION_READ_BUFFER_SIZE|Int
+@@ -974,7 +981,9 @@ PyObject *PyInternetQueryOption(PyObject *self, PyObject *args)
+ 			ret=PyLong_FromUnsignedLong(*(unsigned long *)buf);
+ 			break;
+ 		case INTERNET_OPTION_BYPASS_EDITED_ENTRY:		// @flag INTERNET_OPTION_BYPASS_EDITED_ENTRY|Boolean
++#if !defined(__MINGW32__)
+ 		case INTERNET_OPTION_HTTP_DECODING:		// @flag INTERNET_OPTION_HTTP_DECODING|Boolean
++#endif
+ 		case INTERNET_OPTION_IGNORE_OFFLINE:		// @flag INTERNET_OPTION_IGNORE_OFFLINE|Boolean
+ 			ret=PyBool_FromLong(*(BOOL *)buf);
+ 			break;
+@@ -1157,14 +1166,18 @@ PyObject *PyInternetSetOption(PyObject *self, PyObject *args)
+ 		case INTERNET_OPTION_RECEIVE_TIMEOUT:	// @flag INTERNET_OPTION_RECEIVE_TIMEOUT|Int - timeout in millseconds
+ 												// @flag INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT|Int - timeout in millseconds
+ 		case INTERNET_OPTION_CODEPAGE:		// @flag INTERNET_OPTION_CODEPAGE|Int - Codepage of host part of URL
++#if !defined(__MINGW32__)
+ 		case INTERNET_OPTION_CODEPAGE_PATH:	// @flag INTERNET_OPTION_CODEPAGE_PATH|Codepage for URL
+ 		case INTERNET_OPTION_CODEPAGE_EXTRA:	// @flag INTERNET_OPTION_CODEPAGE_EXTRA|Int - Codepage for path part of URL
++#endif
+ 		case INTERNET_OPTION_CONNECT_RETRIES:		// @flag INTERNET_OPTION_CONNECT_RETRIES|Int - Number of time to try to reconnect to host
+ 		case INTERNET_OPTION_CONNECT_TIMEOUT:		// @flag INTERNET_OPTION_CONNECT_TIMEOUT|Int - Connection timeout in milliseconds
+ 		case INTERNET_OPTION_CONNECTED_STATE:		// @flag INTERNET_OPTION_CONNECTED_STATE|Int - Connection state, INTERNET_STATE_*
+ 		case INTERNET_OPTION_ERROR_MASK:		// @flag INTERNET_OPTION_ERROR_MASK|Int, combination of INTERNET_ERROR_MASK_*
+ 		case INTERNET_OPTION_FROM_CACHE_TIMEOUT:		// @flag INTERNET_OPTION_FROM_CACHE_TIMEOUT|Int - Timeout in ms before cached copy is used
++#if !defined(__MINGW32__)
+ 		case INTERNET_OPTION_IDN:		// @flag INTERNET_OPTION_IDN|Int, INTERNET_FLAG_IDN_*
++#endif
+ 		case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:		// @flag INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER|Int
+ 		case INTERNET_OPTION_MAX_CONNS_PER_SERVER:		// @flag INTERNET_OPTION_MAX_CONNS_PER_SERVER|Int
+ 		case INTERNET_OPTION_READ_BUFFER_SIZE:		// @flag INTERNET_OPTION_READ_BUFFER_SIZE|Int
+@@ -1189,7 +1202,9 @@ PyObject *PyInternetSetOption(PyObject *self, PyObject *args)
+ 				}
+ 			break;
+ 		case INTERNET_OPTION_BYPASS_EDITED_ENTRY:	// @flag INTERNET_OPTION_BYPASS_EDITED_ENTRY|Boolean
++#if !defined(__MINGW32__)
+ 		case INTERNET_OPTION_HTTP_DECODING:		// @flag INTERNET_OPTION_HTTP_DECODING|Boolean
++#endif
+ 		case INTERNET_OPTION_IGNORE_OFFLINE:	// @flag INTERNET_OPTION_IGNORE_OFFLINE|Boolean
+ 			bufsize=sizeof(BOOL);
+ 			buf=malloc(bufsize);
+@@ -1835,7 +1850,11 @@ BOOL PyWinObject_AsINTERNET_CACHE_GROUP_INFO(PyObject *ob, INTERNET_CACHE_GROUP_
+ 			}
+ 		}
+ 	if (bsuccess && GroupName)
++#if defined(__MINGW32__)
++		_tcsncpy(GroupInfo->szGroupName, GroupName, std::min(namelen, (DWORD)GROUPNAME_MAX_LENGTH));
++#else
+ 		_tcsncpy(GroupInfo->szGroupName, GroupName, min(namelen, GROUPNAME_MAX_LENGTH));
++#endif
+ 	Py_DECREF(dummy_tuple);
+ 	PyWinObject_FreeTCHAR(GroupName);
+ 	if (OwnerStorage)
+diff --git a/win32/src/win32net/win32net.h b/win32/src/win32net/win32net.h
+index ae7c690..c961c18 100644
+--- a/win32/src/win32net/win32net.h
++++ b/win32/src/win32net/win32net.h
+@@ -62,15 +62,27 @@ PyObject *PyDoGroupDelMembers(PyObject *self, PyObject *args);
+ 
+ #if WINVER >= 0x0500
+ typedef NET_API_STATUS (NET_API_FUNCTION *NetValidateNamefunc)(LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR, NETSETUP_NAME_TYPE);
+-extern NetValidateNamefunc pfnNetValidateName;
++extern
++#if defined(__MINGW32__)
++"C"
++#endif
++NetValidateNamefunc pfnNetValidateName;
+ 
+ typedef NET_API_STATUS (NET_API_FUNCTION *NetGetJoinInformationfunc)(LPCWSTR, LPWSTR *, PNETSETUP_JOIN_STATUS);
+ extern NetGetJoinInformationfunc pfnNetGetJoinInformation;
+ 
+ typedef NET_API_STATUS (NET_API_FUNCTION *NetValidatePasswordPolicyfunc)(LPCWSTR, LPVOID, NET_VALIDATE_PASSWORD_TYPE, LPVOID, LPVOID *);
+-extern NetValidatePasswordPolicyfunc pfnNetValidatePasswordPolicy;
++extern
++#if defined(__MINGW32__)
++"C"
++#endif
++NetValidatePasswordPolicyfunc pfnNetValidatePasswordPolicy;
+ 
+ typedef NET_API_STATUS (NET_API_FUNCTION *NetValidatePasswordPolicyFreefunc)(LPVOID *);
+-extern NetValidatePasswordPolicyFreefunc pfnNetValidatePasswordPolicyFree;
++extern
++#if defined(__MINGW32__)
++"C"
++#endif
++NetValidatePasswordPolicyFreefunc pfnNetValidatePasswordPolicyFree;
+ 
+ #endif // WINVER
+diff --git a/win32/src/win32pdhmodule.cpp b/win32/src/win32pdhmodule.cpp
+index 94c4ed1..533dad7 100644
+--- a/win32/src/win32pdhmodule.cpp
++++ b/win32/src/win32pdhmodule.cpp
+@@ -15,6 +15,10 @@ generates Windows .hlp files.
+ #include "pdh.h"
+ #include "pdhmsg.h"
+ 
++#if defined(__MINGW32__)
++#include <algorithm>
++#endif
++
+ /*
+ According to MSDN, Pdh calls are thread safe, although there was a bug
+ in Win2k that might make it appear to not be.  Plus, the PyW32* macros
+@@ -1013,12 +1017,21 @@ PDH_STATUS __stdcall PyCounterPathCallback(DWORD_PTR dwArg)
+ 	return rc;
+ }
+ 
++#if defined(__MINGW32__)
++#define SET_BOOL(r, i) { \
++	if (i<seqLen){ \
++		PyObject *subItem = PyTuple_GET_ITEM(flags_tuple, i); \
++		myCfg.cfg. r = PyObject_IsTrue(subItem); \
++	} \
++}
++#else
+ #define SET_BOOL(r, i) { \
+ 	if (i<seqLen){ \
+ 		PyObject *subItem = PyTuple_GET_ITEM(flags_tuple, i); \
+ 		myCfg.cfg.##r = PyObject_IsTrue(subItem); \
+ 	} \
+ }
++#endif
+ 
+ // @pymethod string|win32pdh|BrowseCounters|Displays the counter browsing dialog box so that the user can select the counters to be returned to the caller. 
+ static PyObject *PyBrowseCounters(PyObject *self, PyObject *args, PyObject *kwargs)
+@@ -1082,7 +1095,11 @@ static PyObject *PyBrowseCounters(PyObject *self, PyObject *args, PyObject *kwar
+ 	// Initialize the return buffer if starting path is passed in. (bInitializePath will also be set)
+ 	if (!PyWinObject_AsTCHAR(obInitialPath, &InitialPath, TRUE, &cchInitialPath))
+ 		return NULL;	// Last exit without cleanup
++#if defined(__MINGW32__)
++	myCfg.cfg.cchReturnPathLength = std::max(cchInitialPath+1, 1024UL);
++#else
+ 	myCfg.cfg.cchReturnPathLength = max(cchInitialPath+1, 1024);
++#endif
+ 	myCfg.cfg.szReturnPathBuffer = (TCHAR *)malloc(myCfg.cfg.cchReturnPathLength * sizeof(TCHAR));
+ 	if (myCfg.cfg.szReturnPathBuffer == NULL){
+ 		PyErr_NoMemory();
+diff --git a/win32/src/win32service.i b/win32/src/win32service.i
+index 11a4a23..fab8092 100644
+--- a/win32/src/win32service.i
++++ b/win32/src/win32service.i
+@@ -1818,7 +1818,6 @@ PyObject *PyQueryServiceConfig2(PyObject *self, PyObject *args)
+ #define SERVICE_CONTROL_HARDWAREPROFILECHANGE SERVICE_CONTROL_HARDWAREPROFILECHANGE
+ #define SERVICE_CONTROL_POWEREVENT SERVICE_CONTROL_POWEREVENT
+ #define SERVICE_CONTROL_SESSIONCHANGE SERVICE_CONTROL_SESSIONCHANGE
+-#define SERVICE_CONTROL_PRESHUTDOWN SERVICE_CONTROL_PRESHUTDOWN
+ 
+ 
+ #define SC_MANAGER_ALL_ACCESS SC_MANAGER_ALL_ACCESS 
+@@ -1875,7 +1874,6 @@ PyObject *PyQueryServiceConfig2(PyObject *self, PyObject *args)
+ #define SERVICE_ACCEPT_HARDWAREPROFILECHANGE SERVICE_ACCEPT_HARDWAREPROFILECHANGE
+ #define SERVICE_ACCEPT_POWEREVENT SERVICE_ACCEPT_POWEREVENT
+ #define SERVICE_ACCEPT_SESSIONCHANGE SERVICE_ACCEPT_SESSIONCHANGE
+-#define SERVICE_ACCEPT_PRESHUTDOWN SERVICE_ACCEPT_PRESHUTDOWN
+ 
+ //#define SERVICE_ERROR_IGNORER_IGNORE SERVICE_ERROR_IGNORER_IGNORE
+ #define SERVICE_BOOT_START SERVICE_BOOT_START 
+diff --git a/win32/src/win32trace.cpp b/win32/src/win32trace.cpp
+index 2237094..60e7c83 100644
+--- a/win32/src/win32trace.cpp
++++ b/win32/src/win32trace.cpp
+@@ -35,6 +35,9 @@ See - I told you the implementation was simple :-)
+ 
+ 
+ 
++#if defined(__MINGW32__)
++#include <algorithm>
++#endif
+ 
+ const unsigned long BUFFER_SIZE = 0x20000; // Includes size integer.
+ const TCHAR *MAP_OBJECT_NAME = _T("Global\\PythonTraceOutputMapping");
+@@ -341,7 +344,11 @@ BOOL PyTraceObject::WriteData(const char *data, unsigned len)
+     Py_BEGIN_ALLOW_THREADS
+     const char *data_this = data;
+     while (len) {
++#if defined(__MINGW32__)
++        unsigned len_this = std::min(static_cast<unsigned long>(len), BUFFER_SIZE/2);
++#else
+         unsigned len_this = min(len, BUFFER_SIZE/2);
++#endif
+         BOOL ok = GetMyMutex();
+         if (ok) {
+             // must use types with identical size on win32 and win64
Index: docker/msys/pywin32git.patch
===================================================================
--- docker/msys/pywin32git.patch	(revision 920)
+++ docker/msys/pywin32git.patch	(revision 920)
@@ -0,0 +1,227 @@
+diff --git a/.github/issue_template.md b/.github/issue_template.md
+new file mode 100644
+index 00000000..9c724696
+--- /dev/null
++++ b/.github/issue_template.md
+@@ -0,0 +1,11 @@
++Note that issues in this repository are only for bugs or feature requests in the pywin32.
++
++**If you need support or help using this package, please follow [these instructions](https://github.com/mhammond/pywin32/blob/master/README.md#support)** - support or help requests will be closed without comment.
++
++For all bugs, please provide the following information.
++
++* Expected behavior and actual behavior.
++
++* Steps to reproduce the problem.
++
++* Version of Python and pywin32
+diff --git a/CHANGES.txt b/CHANGES.txt
+index 4b3fcbe3..d209569c 100644
+--- a/CHANGES.txt
++++ b/CHANGES.txt
+@@ -4,6 +4,10 @@ Generally created by hand after running:
+    hg log -rb2xx: > log.out
+ However contributors are encouraged to add their own entries for their work.
+ 
++Since build 224:
++----------------
++* PythonWin is now able to start with non-English active keyboard layout.
++
+ Since build 223:
+ ----------------
+ * Built with a released version of Python 3.7, which fixes various date related
+diff --git a/Pythonwin/pywin/scintilla/keycodes.py b/Pythonwin/pywin/scintilla/keycodes.py
+index 6b783761..d9021828 100644
+--- a/Pythonwin/pywin/scintilla/keycodes.py
++++ b/Pythonwin/pywin/scintilla/keycodes.py
+@@ -35,7 +35,9 @@ def get_vk(chardesc):
+         # it is a character.
+         info = win32api.VkKeyScan(chardesc)
+         if info==-1:
+-            return None, None
++            # Note: returning None, None causes an error when keyboard layout is non-English, see the report below
++            # https://stackoverflow.com/questions/45138084/pythonwin-occasionally-gives-an-error-on-opening
++            return 0, 0
+         vk = win32api.LOBYTE(info)
+         state = win32api.HIBYTE(info)
+         modifiers = 0
+diff --git a/appveyor.yml b/appveyor.yml
+index a45bdb39..f84cdbc4 100644
+--- a/appveyor.yml
++++ b/appveyor.yml
+@@ -20,6 +20,8 @@ environment:
+       PYTHON_MINOR: 5
+     - PYTHON_MAJOR: 3
+       PYTHON_MINOR: 6
++    - PYTHON_MAJOR: 3
++      PYTHON_MINOR: 7
+ 
+ install:
+   # Prepare environment
+@@ -42,6 +44,7 @@ init:
+   # Following the matrix here: https://wiki.python.org/moin/WindowsCompilers#Which_Microsoft_Visual_C.2B-.2B-_compiler_to_use_with_a_specific_Python_version_.3F
+   - if "%PLATFORM%"=="x86" set VC_ARCH=x86
+   - if "%PLATFORM%"=="x64" set VC_ARCH=amd64
++  - if "%PYTHON_MAJOR%"=="3" if "%PYTHON_MINOR%"=="7" set VC_VERSION=14.0
+   - if "%PYTHON_MAJOR%"=="3" if "%PYTHON_MINOR%"=="6" set VC_VERSION=14.0
+   - if "%PYTHON_MAJOR%"=="3" if "%PYTHON_MINOR%"=="5" set VC_VERSION=14.0
+   - if "%PYTHON_MAJOR%"=="3" if "%PYTHON_MINOR%"=="4" set VC_VERSION=10.0
+diff --git a/setup.py b/setup.py
+index 8c397e1e..7c35d909 100644
+--- a/setup.py
++++ b/setup.py
+@@ -1883,6 +1883,7 @@ com_extensions += [
+                     depends=["%(internet)s/internet_pch.h" % dirs]),
+     WinExt_win32com('mapi', libraries="advapi32", pch_header="PythonCOM.h",
+                     include_dirs=["%(mapi)s/mapi_headers" % dirs],
++                    optional_headers=['edkmdb.h', 'edkguid.h'],
+                     sources=("""
+                         %(mapi)s/mapi.i                 %(mapi)s/mapi.cpp
+                         %(mapi)s/PyIABContainer.i       %(mapi)s/PyIABContainer.cpp
+@@ -1911,6 +1912,7 @@ com_extensions += [
+                         """ % dirs).split()),
+     WinExt_win32com_mapi('exchange', libraries="advapi32",
+                          include_dirs=["%(mapi)s/mapi_headers" % dirs],
++                         optional_headers=['edkmdb.h', 'edkguid.h'],
+                          sources=("""
+                                   %(mapi)s/exchange.i         %(mapi)s/exchange.cpp
+                                   %(mapi)s/PyIExchangeManageStore.i %(mapi)s/PyIExchangeManageStore.cpp
+@@ -2438,6 +2440,17 @@ cmdclass = { 'install': my_install,
+              'build_scripts' : my_build_scripts,
+            }
+ 
++classifiers = [ 'Environment :: Win32 (MS Windows)',
++	            'Intended Audience :: Developers',
++	            'License :: OSI Approved :: Python Software Foundation License',
++	            'Operating System :: Microsoft :: Windows',
++	            'Programming Language :: Python :: 2.7',
++	            'Programming Language :: Python :: 3.5',
++	            'Programming Language :: Python :: 3.6',
++	            'Programming Language :: Python :: 3.7',
++	            'Programming Language :: Python :: Implementation :: CPython',
++	          ]
++
+ dist = setup(name="pywin32",
+       version=str(build_id),
+       description="Python for Window Extensions",
+@@ -2449,6 +2462,7 @@ dist = setup(name="pywin32",
+       author_email = "mhammond@skippinet.com.au",
+       url="https://github.com/mhammond/pywin32",
+       license="PSF",
++      classifiers = classifiers,
+       cmdclass = cmdclass,
+       options = {"bdist_wininst":
+                     {"install_script": "pywin32_postinstall.py",
+diff --git a/win32/Lib/win32con.py b/win32/Lib/win32con.py
+index a37967f7..eb6b8a90 100644
+--- a/win32/Lib/win32con.py
++++ b/win32/Lib/win32con.py
+@@ -2060,6 +2060,9 @@ PROCESS_CREATE_PROCESS = (128)
+ PROCESS_SET_QUOTA = (256)
+ PROCESS_SET_INFORMATION = (512)
+ PROCESS_QUERY_INFORMATION = (1024)
++PROCESS_SUSPEND_RESUME = (2048)
++PROCESS_QUERY_LIMITED_INFORMATION = (4096)
++PROCESS_SET_LIMITED_INFORMATION = (8192)
+ PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 4095)
+ THREAD_TERMINATE = (1)
+ THREAD_SUSPEND_RESUME = (2)
+@@ -2070,6 +2073,9 @@ THREAD_QUERY_INFORMATION = (64)
+ THREAD_SET_THREAD_TOKEN = (128)
+ THREAD_IMPERSONATE = (256)
+ THREAD_DIRECT_IMPERSONATION = (512)
++THREAD_SET_LIMITED_INFORMATION = (1024)
++THREAD_QUERY_LIMITED_INFORMATION = (2048)
++THREAD_RESUME = (4096)
+ TLS_MINIMUM_AVAILABLE = 64
+ EVENT_MODIFY_STATE = 2
+ MUTANT_QUERY_STATE = 1
+diff --git a/win32/Lib/win32timezone.py b/win32/Lib/win32timezone.py
+index 83a119dc..6d65af7d 100644
+--- a/win32/Lib/win32timezone.py
++++ b/win32/Lib/win32timezone.py
+@@ -715,14 +715,22 @@ class TimeZoneInfo(datetime.tzinfo):
+ 	@staticmethod
+ 	def _get_indexed_time_zone_keys(index_key='Index'):
+ 		"""
+-		Get the names of the registry keys indexed by a value in that key.
++		Get the names of the registry keys indexed by a value in that key,
++		ignoring any keys for which that value is empty or missing.
+ 		"""
+ 		key_names = list(TimeZoneInfo._get_time_zone_key_names())
++
+ 		def get_index_value(key_name):
+ 			key = TimeZoneInfo._get_time_zone_key(key_name)
+-			return key[index_key]
++			return key.get(index_key)
++
+ 		values = map(get_index_value, key_names)
+-		return zip(values, key_names)
++
++		return (
++			(value, key_name)
++			for value, key_name in zip(values, key_names)
++			if value
++		)
+ 
+ 	@staticmethod
+ 	def get_sorted_time_zone_names():
+@@ -786,25 +794,6 @@ class _RegKeyDict(dict):
+ 		except WindowsError: pass
+ 
+ 
+-# for backward compatibility
+-def deprecated(func, name='Unknown'):
+-	"""This is a decorator which can be used to mark functions
+-	as deprecated. It will result in a warning being emmitted
+-	when the function is used."""
+-	def newFunc(*args, **kwargs):
+-		warnings.warn("Call to deprecated function %s." % name,
+-			category=DeprecationWarning)
+-		return func(*args, **kwargs)
+-	newFunc.__name__ = func.__name__
+-	newFunc.__doc__ = func.__doc__
+-	newFunc.__dict__.update(func.__dict__)
+-	return newFunc
+-
+-GetTimeZoneNames = deprecated(TimeZoneInfo._get_time_zone_key_names, 'GetTimeZoneNames')
+-GetIndexedTimeZoneNames = deprecated(TimeZoneInfo._get_indexed_time_zone_keys, 'GetIndexedTimeZoneNames')
+-GetSortedTimeZoneNames = deprecated(TimeZoneInfo.get_sorted_time_zone_names, 'GetSortedTimeZoneNames')
+-# end backward compatibility
+-
+ def utcnow():
+ 	"""
+ 	Return the UTC time now with timezone awareness as enabled
+@@ -860,7 +849,7 @@ def resolveMUITimeZone(spec):
+ 	spec should be of the format @path,-stringID[;comment]
+ 	see http://msdn2.microsoft.com/en-us/library/ms725481.aspx for details
+ 	"""
+-	pattern = re.compile('@(?P<dllname>.*),-(?P<index>\d+)(?:;(?P<comment>.*))?')
++	pattern = re.compile(r'@(?P<dllname>.*),-(?P<index>\d+)(?:;(?P<comment>.*))?')
+ 	matcher = pattern.match(spec)
+ 	assert matcher, 'Could not parse MUI spec'
+ 
+diff --git a/win32/Lib/winnt.py b/win32/Lib/winnt.py
+index 15584efa..021a32b1 100644
+--- a/win32/Lib/winnt.py
++++ b/win32/Lib/winnt.py
+@@ -194,6 +194,9 @@ PROCESS_CREATE_PROCESS = (128)
+ PROCESS_SET_QUOTA = (256)
+ PROCESS_SET_INFORMATION = (512)
+ PROCESS_QUERY_INFORMATION = (1024)
++PROCESS_SUSPEND_RESUME = (2048)
++PROCESS_QUERY_LIMITED_INFORMATION = (4096)
++PROCESS_SET_LIMITED_INFORMATION = (8192)
+ MAXIMUM_PROCESSORS = 32
+ THREAD_TERMINATE = (1)
+ THREAD_SUSPEND_RESUME = (2)
+@@ -204,6 +207,9 @@ THREAD_QUERY_INFORMATION = (64)
+ THREAD_SET_THREAD_TOKEN = (128)
+ THREAD_IMPERSONATE = (256)
+ THREAD_DIRECT_IMPERSONATION = (512)
++THREAD_SET_LIMITED_INFORMATION = (1024)
++THREAD_QUERY_LIMITED_INFORMATION = (2048)
++THREAD_RESUME = (4096)
+ JOB_OBJECT_ASSIGN_PROCESS = (1)
+ JOB_OBJECT_SET_ATTRIBUTES = (2)
+ JOB_OBJECT_QUERY = (4)
Index: docker/msys/setup.sh
===================================================================
--- docker/msys/setup.sh	(revision 920)
+++ docker/msys/setup.sh	(revision 920)
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+set -e -u
+
+pacman -S --noconfirm mc patch unzip mingw-w64-i686-python3 mingw-w64-i686-python3-setuptools mingw-w64-i686-gcc  mingw-w64-i686-gtk3 mingw-w64-i686-python3-lxml mingw-w64-i686-cmake mingw-w64-i686-make mingw-w64-i686-python3-pip mingw-w64-i686-python3-pillow mingw-w64-i686-python3-gobject mingw-w64-i686-python3-cffi
+pacman -Scc --noconfirm
+
+pip3 install jsonrpclib-pelix
+
+echo "Building PyWin32"
+
+cd /build
+
+wget -O - https://github.com/mhammond/pywin32/archive/b224.tar.gz | gzip -dc | tar xf -
+cd pywin32-b224
+patch -p1 < ../pywin32git.patch
+patch -p1 < ../pywin32.patch
+python3 setup.py build
+python3 setup.py install
+
+echo "Building CEFPython"
+
+cd /build
+
+wget -O - http://opensource.spotify.com/cefbuilds/cef_binary_3.3359.1774.gd49d25f_windows32.tar.bz2 | bzip2 -dc | tar xf -
+cd cef_binary_3.3359.1774.gd49d25f_windows32
+
+patch -p1 < ../cef_binary_3.3359.1774.gd49d25f_windows32.patch
+mv tests tests.orig
+
+mkdir build
+cd build
+/usr/bin/env PATH=/mingw32/bin:/usr/local/bin::/c/Windows/System32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0 cmake  -G "MinGW Makefiles" ..
+cd libcef_dll_wrapper
+mingw32-make
+
+cd /build
+
+wget -O - https://github.com/cztomczak/cefpython/archive/v66.0.tar.gz | gzip -dc | tar xf -
+cd cefpython-66.0
+
+patch -p1 < ../cefpython-66.0.patch
+
+mkdir -p build
+cd build
+
+wget https://github.com/cztomczak/cefpython/releases/download/v66-upstream/cef66_3.3359.1774.gd49d25f_win32.zip
+unzip cef66_3.3359.1774.gd49d25f_win32.zip
+rm cef66_3.3359.1774.gd49d25f_win32.zip
+
+cp /build/cef_binary_3.3359.1774.gd49d25f_windows32/build/libcef_dll_wrapper/libcef_dll_wrapper.a cef66_3.3359.1774.gd49d25f_win32/lib
+
+pip3 install -r ../tools/requirements.txt
+
+python3 ../tools/build.py --no-run-tests --no-run-examples 66.0  || true
+python3 ../tools/build.py --no-run-tests --no-run-examples 66.0
+
+echo "Building Py2EXE"
+
+cd /build
+
+wget -O - https://github.com/albertosottile/py2exe/archive/v0.9.3.0.tar.gz | gzip -dc | tar xf -
+cd py2exe-0.9.3.0
+patch -p1 < ../py2exe.patch
+python3 setup.py build
+python3 setup.py install
+
+cd /
+rm -rf /build
Index: keinst.bat
===================================================================
--- makeinst.bat	(revision 682)
+++ 	(revision )
@@ -1,14 +1,0 @@
-set MSVCRDIR=c:\windows\winsxs\x86_Microsoft.VC90.CRT*9.0.21022.8*
-set GTKRTDIR=c:\Python27\Lib\site-packages\gtk-2.0\runtime
-set CEFDIR=c:\Python27\Lib\site-packages\cefpython3
-set CHROMEDRIVER=c:\tmp\chromedriver.exe
-set NSISDIR=C:\Program Files\NSIS
-
-python setup.py py2exe
-
-del dist\library\selenium\webdriver\chrome\service.pyc
-copy patches\library\selenium\webdriver\chrome\service.py dist\library\selenium\webdriver\chrome\service.py
-python -m compileall dist\library\selenium\webdriver\chrome\service.py
-del dist\library\selenium\webdriver\chrome\service.py
-
-"%NSISDIR%\makensis" mlx.nsi
Index: makeinst.sh
===================================================================
--- makeinst.sh	(revision 937)
+++ makeinst.sh	(revision 937)
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+#set MSVCRDIR=c:\windows\winsxs\x86_Microsoft.VC90.CRT*9.0.21022.8*
+if test "${WINE}" = "yes"; then
+    cdrive="/root/.wine/drive_c/"
+    MINGW32DIR="c:/msys64/mingw32"
+
+    export GTKRTDIR="${MINGW32DIR}"
+    export CEFDIR="${MINGW32DIR}/lib/python3.7/site-packages/cefpython3"
+
+    export PYTHONHASHSEED=1234
+    export PYTHONIOENCODING=utf8
+    export PYTHONUTF8=1
+
+    wine "${cdrive}/msys64/mingw32/bin/python3.exe" setup.py py2exe
+
+    wine "${cdrive}/Program Files/NSIS/makensis.exe" mlx.nsi
+else
+    export GTKRTDIR=/mingw32
+    export CEFDIR=/mingw32/lib/python3.7/site-packages/cefpython3
+#set CHROMEDRIVER=c:\tmp\chromedriver.exe
+    export NSISDIR=/c/Program Files/NSIS
+
+    python3 setup.py py2exe
+    "$NSISDIR/makensis.exe" mlx.nsi
+fi
+
+#del dist\library\selenium\webdriver\chrome\service.pyc
+#copy patches\library\selenium\webdriver\chrome\service.py dist\library\selenium\webdriver\chrome\service.py
+#python -m compileall dist\library\selenium\webdriver\chrome\service.py
+#del dist\library\selenium\webdriver\chrome\service.py
Index: makesdist.sh
===================================================================
--- makesdist.sh	(revision 281)
+++ makesdist.sh	(revision 940)
@@ -2,3 +2,3 @@
 
 make
-python setup.py sdist
+python3 setup.py sdist
Index: runmlx.sh
===================================================================
--- runmlx.sh	(revision 577)
+++ runmlx.sh	(revision 933)
@@ -8,3 +8,6 @@
 https_proxy=
 
-exec python -m runmlx "$@"
+FORCE_PYGOBJECT=true
+export FORCE_PYGOBJECT
+
+exec python3 -m runmlx "$@"
Index: setup.py
===================================================================
--- setup.py	(revision 916)
+++ setup.py	(revision 947)
@@ -5,4 +5,5 @@
 from glob import glob
 from distutils.core import setup
+from pathlib import Path
 
 scriptdir=os.path.dirname(sys.argv[0])
@@ -11,4 +12,33 @@
 import mlx.const
 import mlx.update
+
+defaultManifest="""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="asInvoker"/>
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!--The ID below indicates application support for Windows Vista -->
+      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+      <!--The ID below indicates application support for Windows 7 -->
+      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+      <!--The ID below indicates application support for Windows 8 -->
+      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+      <!--The ID below indicates application support for Windows 8.1 -->
+      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+      <!--The ID below indicates application support for Windows 10 -->
+      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+    </application>
+  </compatibility>
+</assembly>"""
+
+adminManifest=defaultManifest.replace("asInvoker", "requireAdministrator")
+
+RT_MANIFEST=24
 
 data_files = [("sounds", glob(os.path.join("sounds", "*.*")))]
@@ -40,22 +70,55 @@
     gtkRuntimeDir = os.environ["GTKRTDIR"] if "GTKRTDIR" in os.environ else None
     if gtkRuntimeDir:
-        path = os.path.join("lib", "gtk-2.0", "2.10.0", "engines")
-        data_files.append((os.path.join("library", path),
-                           [os.path.join(gtkRuntimeDir, path, "libwimp.dll")]))
-
-        path = os.path.join("share", "themes", "MS-Windows", "gtk-2.0")
-        data_files.append((os.path.join("library", path),
-                           glob(os.path.join(gtkRuntimeDir, path, "*"))))
-
-        path = os.path.join("share", "locale", "hu", "LC_MESSAGES")
-        data_files.append((os.path.join("library", path),
-                           glob(os.path.join(gtkRuntimeDir, path, "*"))))
-        path = os.path.join("share", "icons", "hicolor")
-        data_files.append((os.path.join("library", path),
-                           glob(os.path.join(gtkRuntimeDir, path, "*"))))
+        if gtkRuntimeDir.endswith("/mingw32"):
+            path = os.path.join("lib", "girepository-1.0")
+            data_files.append((path,
+                               glob(os.path.join(gtkRuntimeDir, path, "*"))))
+
+            files = {}
+
+            for components in [ ["lib", "girepository-1.0"],
+                                ["lib", "gdk-pixbuf-2.0", "2.10.0"],
+                                ["share", "icons"],
+                                ["share", "locale", "hu"],
+                                ["share", "locale", "en"],
+                                ["share", "themes"],
+                                ["share", "glib-2.0", "schemas"]]:
+                path = os.path.join(*components)
+                p = Path(os.path.join(gtkRuntimeDir, path))
+                for f in p.glob("**/*"):
+                    if f.is_file():
+                        d = os.path.join(path, str(f.parent.relative_to(p)))
+                        if d in files:
+                            files[d].append(str(f))
+                        else:
+                            files[d] = [str(f)]
+
+            for path in files:
+                data_files.append((path, files[path]))
+            data_files.append(("",
+                               [os.path.join(gtkRuntimeDir, "bin", "librsvg-2-2.dll"),
+                                os.path.join(gtkRuntimeDir, "bin", "libcroco-0.6-3.dll")]))
+        else:
+            path = os.path.join("lib", "gtk-2.0", "2.10.0", "engines")
+            data_files.append((os.path.join("library", path),
+                               [os.path.join(gtkRuntimeDir, path, "libwimp.dll")]))
+
+            path = os.path.join("share", "themes", "MS-Windows", "gtk-2.0")
+            data_files.append((os.path.join("library", path),
+                               glob(os.path.join(gtkRuntimeDir, path, "*"))))
+
+            path = os.path.join("share", "locale", "hu", "LC_MESSAGES")
+            data_files.append((os.path.join("library", path),
+                               glob(os.path.join(gtkRuntimeDir, path, "*"))))
+            path = os.path.join("share", "icons", "hicolor")
+            data_files.append((os.path.join("library", path),
+                               glob(os.path.join(gtkRuntimeDir, path, "*"))))
 
     cefDir = os.environ.get("CEFDIR")
     if cefDir:
-        for fileName in ["icudt.dll", "subprocess.exe"]:
+        for fileName in ["icudtl.dat", "subprocess.exe", "natives_blob.bin",
+                         "snapshot_blob.bin", "v8_context_snapshot.bin",
+                         "cef.pak", "cef_100_percent.pak",
+                         "cef_200_percent.pak", "cef_extensions.pak"]:
             data_files.append(("", [os.path.join(cefDir, fileName)]))
 
@@ -65,42 +128,62 @@
     if os.getenv("WINE")=="yes":
         winsysdir=os.getenv("WINSYSDIR")
-        data_files.append(("", [os.path.join(winsysdir, "python27.dll")]))
-        data_files.append(("library", [
-                            os.path.join(winsysdir, "pywintypes27.dll"),
-                            os.path.join(winsysdir, "WINHTTP.dll")]))
 
         if gtkRuntimeDir:
             gtkBinDir = os.path.join(gtkRuntimeDir, "bin")
-            data_files.append(("library", [
-                                os.path.join(gtkBinDir, "freetype6.dll"),
-                                os.path.join(gtkBinDir, "intl.dll"),
-                                os.path.join(gtkBinDir, "zlib1.dll"),
+            data_files.append(("", [
+                                os.path.join(gtkBinDir, "libatk-1.0-0.dll"),
+                                os.path.join(gtkBinDir, "libbz2-1.dll"),
+                                os.path.join(gtkBinDir, "libcairo-2.dll"),
+                                os.path.join(gtkBinDir, "libcairo-gobject-2.dll"),
+                                os.path.join(gtkBinDir, "libcroco-0.6-3.dll"),
+                                os.path.join(gtkBinDir, "libcrypto-1_1.dll"),
+                                os.path.join(gtkBinDir, "libdatrie-1.dll"),
+                                os.path.join(gtkBinDir, "libepoxy-0.dll"),
+                                os.path.join(gtkBinDir, "libexpat-1.dll"),
+                                os.path.join(gtkBinDir, "libexslt-0.dll"),
+                                os.path.join(gtkBinDir, "libffi-6.dll"),
+                                os.path.join(gtkBinDir, "libfontconfig-1.dll"),
+                                os.path.join(gtkBinDir, "libfreetype-6.dll"),
+                                os.path.join(gtkBinDir, "libfribidi-0.dll"),
+                                os.path.join(gtkBinDir, "libgcc_s_dw2-1.dll"),
+                                os.path.join(gtkBinDir, "libgdk_pixbuf-2.0-0.dll"),
+                                os.path.join(gtkBinDir, "libgio-2.0-0.dll"),
+                                os.path.join(gtkBinDir, "libgirepository-1.0-1.dll"),
                                 os.path.join(gtkBinDir, "libglib-2.0-0.dll"),
-                                os.path.join(gtkBinDir, "libatk-1.0-0.dll"),
-                                os.path.join(gtkBinDir, "libcairo-2.dll"),
-                                os.path.join(gtkBinDir, "libexpat-1.dll"),
-                                os.path.join(gtkBinDir, "libpangowin32-1.0-0.dll"),
-                                os.path.join(gtkBinDir, "libgio-2.0-0.dll"),
-                                os.path.join(gtkBinDir, "libgdk-win32-2.0-0.dll"),
-                                os.path.join(gtkBinDir, "libpng14-14.dll"),
+                                os.path.join(gtkBinDir, "libgmodule-2.0-0.dll"),
                                 os.path.join(gtkBinDir, "libgobject-2.0-0.dll"),
-                                os.path.join(gtkBinDir, "libgdk_pixbuf-2.0-0.dll"),
-                                os.path.join(gtkBinDir, "libfontconfig-1.dll"),
-                                os.path.join(gtkBinDir, "libpangoft2-1.0-0.dll"),
-                                os.path.join(gtkBinDir, "libgmodule-2.0-0.dll"),
+                                os.path.join(gtkBinDir, "libgraphite2.dll"),
+                                os.path.join(gtkBinDir, "libharfbuzz-0.dll"),
+                                os.path.join(gtkBinDir, "libiconv-2.dll"),
+                                os.path.join(gtkBinDir, "libintl-8.dll"),
+                                os.path.join(gtkBinDir, "liblzma-5.dll"),
+                                os.path.join(gtkBinDir, "libmpdec-2.dll"),
                                 os.path.join(gtkBinDir, "libpango-1.0-0.dll"),
                                 os.path.join(gtkBinDir, "libpangocairo-1.0-0.dll"),
-                                os.path.join(gtkBinDir, "libgtk-win32-2.0-0.dll"),
-                                os.path.join(gtkBinDir, "libgthread-2.0-0.dll")
+                                os.path.join(gtkBinDir, "libpangoft2-1.0-0.dll"),
+                                os.path.join(gtkBinDir, "libpangowin32-1.0-0.dll"),
+                                os.path.join(gtkBinDir, "libpcre-1.dll"),
+                                os.path.join(gtkBinDir, "libpixman-1-0.dll"),
+                                os.path.join(gtkBinDir, "libpng16-16.dll"),
+                                os.path.join(gtkBinDir, "librsvg-2-2.dll"),
+                                os.path.join(gtkBinDir, "libssl-1_1.dll"),
+                                os.path.join(gtkBinDir, "libssp-0.dll"),
+                                os.path.join(gtkBinDir, "libstdc++-6.dll"),
+                                os.path.join(gtkBinDir, "libthai-0.dll"),
+                                os.path.join(gtkBinDir, "libwinpthread-1.dll"),
+                                os.path.join(gtkBinDir, "libxml2-2.dll"),
+                                os.path.join(gtkBinDir, "libxslt-1.dll"),
+                                os.path.join(gtkBinDir, "zlib1.dll"),
                               ]))
         if cefDir:
-            data_files.append(("library", [
-                                os.path.join(cefDir, "libcef.dll")
+            data_files.append(("", [
+                                os.path.join(cefDir, "libcef.dll"),
+                                os.path.join(cefDir, "chrome_elf.dll")
                               ]))
 
-    print data_files
+    print(data_files)
 
     with open("mlx-common.nsh", "wt") as f:
-            print >>f, '!define MLX_VERSION "%s"' % (mlx.const.VERSION)
+            print('!define MLX_VERSION "%s"' % (mlx.const.VERSION), file=f)
             f.close()
 else:
@@ -129,10 +212,11 @@
       requires = ["pyuipc", "xplra"],
       windows = [{ "script" : "runmlx.py",
-                   "icon_resources" : [(1, "logo.ico")]},
+                   "icon_resources" : [(1, "logo.ico")],
+                   "other_resources": [(RT_MANIFEST, 1, defaultManifest)]},
                  { "script" : "mlxupdate.py",
-                   "uac_info" : "requireAdministrator"}],
-      options = { "py2exe" : { "includes": "gio, pango, atk, pangocairo, lxml._elementpath",
+                   "other_resources": [(RT_MANIFEST, 1, adminManifest)]}],
+      options = { "py2exe" : { "packages" : "gi, lxml",
                                "skip_archive": True} },
-      zipfile = "library/.",
+      zipfile = "library",
       data_files = data_files,
       platforms = ["Win32", "Linux"],
@@ -141,8 +225,6 @@
 
 if os.name=="nt":
-    os.rename(os.path.join(scriptdir, "dist", "library", "libcef.dll"),
-              os.path.join(scriptdir, "dist", "libcef.dll"))
     mlx.update.buildManifest(os.path.join(scriptdir, "dist"))
     with open(os.path.join(scriptdir, "dist", "Uninstall.conf"), "wt") as f:
-        print >> f, "StartMenuFolder=MAVA Logger X"
-        print >> f, "LinkName=MAVA Logger X"
+        print("StartMenuFolder=MAVA Logger X", file=f)
+        print("LinkName=MAVA Logger X", file=f)
Index: src/mlx/acars.py
===================================================================
--- src/mlx/acars.py	(revision 743)
+++ src/mlx/acars.py	(revision 919)
@@ -1,4 +1,4 @@
 
-import const
+from . import const
 
 #------------------------------------------------------------------------------
Index: src/mlx/acft.py
===================================================================
--- src/mlx/acft.py	(revision 905)
+++ src/mlx/acft.py	(revision 919)
@@ -1,9 +1,9 @@
 
-import const
-import gates
-import checks
-import fs
-from i18n import xstr
-import util
+from . import const
+from . import gates
+from . import checks
+from . import fs
+from .i18n import xstr
+from . import util
 
 import sys
@@ -308,5 +308,5 @@
               ("-" if value is None else "enabled" if value else "disabled",)
         elif dt!=DERATE_NONE:
-            print "mlx.acft.getDerateLine: invalid derate type: " + dt
+            print("mlx.acft.getDerateLine: invalid derate type: " + dt)
 
         return None
@@ -343,5 +343,5 @@
                                   self._aircraftState, aircraftState)
                 except:
-                    print >> sys.stderr, "Checker", checker, "failed"
+                    print("Checker", checker, "failed", file=sys.stderr)
                     traceback.print_exc()
 
@@ -351,5 +351,5 @@
             self._minVS = min(self._minVS, aircraftState.vs)
         except:
-            print >> sys.stderr, "Failed to handle the state"
+            print("Failed to handle the state", file=sys.stderr)
             traceback.print_exc()
         finally:
@@ -403,5 +403,5 @@
                     self._logQNH(aircraftState)
             elif newStage==const.STAGE_GOAROUND:
-                from logger import Logger
+                from .logger import Logger
                 self._flight.handleFault("goaround",
                                          aircraftState.timestamp,
@@ -1284,47 +1284,47 @@
     value = SmoothedValue()
 
-    print "Adding 1, 12.0"
+    print("Adding 1, 12.0")
     value.add(1, 12.0)
-    print value.get()
-
-    print "Adding 1, 15.0"
+    print(value.get())
+
+    print("Adding 1, 15.0")
     value.add(1, 15.0)
-    print value.get()
-
-    print "Adding 2, 18.0"
+    print(value.get())
+
+    print("Adding 2, 18.0")
     value.add(2, 18.0)
-    print value.get()
-
-    print "Adding 2, 20.0"
+    print(value.get())
+
+    print("Adding 2, 20.0")
     value.add(2, 20.0)
-    print value.get()
-
-    print "Adding 5, 22.0"
+    print(value.get())
+
+    print("Adding 5, 22.0")
     value.add(5, 22.0)
-    print value.get()
-
-    print "Adding 5, 25.0"
+    print(value.get())
+
+    print("Adding 5, 25.0")
     value.add(5, 25.0)
-    print value.get()
-
-    print "Adding 5, 29.0"
+    print(value.get())
+
+    print("Adding 5, 29.0")
     value.add(5, 29.0)
-    print value.get()
-
-    print "Adding 5, 21.0"
+    print(value.get())
+
+    print("Adding 5, 21.0")
     value.add(5, 21.0)
-    print value.get()
-
-    print "Adding 5, 26.0"
+    print(value.get())
+
+    print("Adding 5, 26.0")
     value.add(5, 26.0)
-    print value.get()
-
-    print "Adding 2, 30.0"
+    print(value.get())
+
+    print("Adding 2, 30.0")
     value.add(2, 30.0)
-    print value.get()
-
-    print "Adding 2, 55.0"
+    print(value.get())
+
+    print("Adding 2, 55.0")
     value.add(2, 55.0)
-    print value.get()
-
-#---------------------------------------------------------------------------------------
+    print(value.get())
+
+#---------------------------------------------------------------------------------------
Index: src/mlx/airports.py
===================================================================
--- src/mlx/airports.py	(revision 325)
+++ src/mlx/airports.py	(revision 919)
@@ -88,11 +88,11 @@
 
 if __name__ == "__main__":
-    for (town, airport) in airportNames.itervalues():
-        print town, airport
-    print getWelcomeMessage("LIRF")
-    print getWelcomeMessage("LHDC")
-    print getWelcomeMessage("LIRN")
-    print getWelcomeMessage("LHBP")
-    print getWelcomeMessage("EDDF")
+    for (town, airport) in airportNames.values():
+        print(town, airport)
+    print(getWelcomeMessage("LIRF"))
+    print(getWelcomeMessage("LHDC"))
+    print(getWelcomeMessage("LIRN"))
+    print(getWelcomeMessage("LHBP"))
+    print(getWelcomeMessage("EDDF"))
 
 #-----------------------------------------------------------------------------
Index: src/mlx/checks.py
===================================================================
--- src/mlx/checks.py	(revision 912)
+++ src/mlx/checks.py	(revision 919)
@@ -1,8 +1,8 @@
 
-import fs
-import const
-import util
-from acars import ACARS
-from sound import startSound
+from . import fs
+from . import const
+from . import util
+from .acars import ACARS
+from .sound import startSound
 
 import time
@@ -129,9 +129,9 @@
         """Callback for ACARS sending."""
         if returned:
-            print "Sent online ACARS"
+            print("Sent online ACARS")
             self._lastSent = time.time() if self._lastSent is None \
                              else self._lastSent + ACARSSender.INTERVAL
         else:
-            print "Failed to send the ACARS"
+            print("Failed to send the ACARS")
         self._sending = False
 
@@ -517,6 +517,6 @@
     def getMessage(logName, frequency, obs):
         """Get the message for the given NAV radio setting."""
-        message = u"%-5s %s" % (logName + ":", frequency)
-        if obs is not None: message += u" (%03d\u00b0)" % (obs,)
+        message = "%-5s %s" % (logName + ":", frequency)
+        if obs is not None: message += " (%03d\u00b0)" % (obs,)
         return message
 
@@ -747,7 +747,7 @@
         message = what
         if value is None:
-            message += u" cannot be detected, will not log"
+            message += " cannot be detected, will not log"
         else:
-            message += u": " + format % (value,)
+            message += ": " + format % (value,)
         logger.message(timestamp, message)
 
@@ -767,6 +767,6 @@
     def _logAPHeading(logger, timestamp, state):
         """Log the AP heading."""
-        APLogger._logNumeric(logger, timestamp, u"AP heading",
-                             u"%03.0f\u00b0", state.apHeading)
+        APLogger._logNumeric(logger, timestamp, "AP heading",
+                             "%03.0f\u00b0", state.apHeading)
 
     @staticmethod
@@ -779,6 +779,6 @@
     def _logAPAltitude(logger, timestamp, state):
         """Log the AP heading."""
-        APLogger._logNumeric(logger, timestamp, u"AP altitude",
-                             u"%.0f ft", state.apAltitude)
+        APLogger._logNumeric(logger, timestamp, "AP altitude",
+                             "%.0f ft", state.apAltitude)
 
     def __init__(self):
Index: src/mlx/common.py
===================================================================
--- src/mlx/common.py	(revision 800)
+++ src/mlx/common.py	(revision 942)
@@ -22,11 +22,10 @@
 #-------------------------------------------------------------------------------
 
-# Due to CEF, PyGTK is the default
-if "FORCE_PYGOBJECT" not in os.environ:
-    print "Using PyGTK"
+if "FORCE_PYGTK" in os.environ:
+    print("Using PyGTK")
     pygobject = False
     import gobject
 else:
-    print "Using PyGObject"
+    print("Using PyGObject")
     pygobject = True
 
Index: src/mlx/config.py
===================================================================
--- src/mlx/config.py	(revision 738)
+++ src/mlx/config.py	(revision 919)
@@ -1,11 +1,11 @@
 # -*- encoding: utf-8 -*-
 
-import const
-from util import secondaryInstallation, utf2unicode
+from . import const
+from .util import secondaryInstallation, utf2unicode
 
 import os
 import sys
 import traceback
-import ConfigParser
+import configparser
 
 ## @package mlx.config
@@ -163,5 +163,5 @@
         baseName = "callouts." + const.icaoCodes[aircraftType] + "."
         index = 0
-        for (altitude, path) in self._mapping.iteritems():
+        for (altitude, path) in self._mapping.items():
             option = baseName + str(index)
             config.set(ApproachCallouts.SECTION, option,
@@ -171,9 +171,9 @@
     def getAltitudes(self, descending = True):
         """Get the altitudes in decreasing order by default."""
-        altitudes = self._mapping.keys()
+        altitudes = list(self._mapping.keys())
         altitudes.sort(reverse = descending)
         return altitudes
 
-    def __nonzero__(self):
+    def __bool__(self):
         """Return if there is anything in the mapping."""
         return not not self._mapping
@@ -704,5 +704,5 @@
         """Load the configuration from its default location."""
         try:
-            config = ConfigParser.RawConfigParser()
+            config = configparser.RawConfigParser()
             config.read(configPath)
         except:
@@ -806,5 +806,5 @@
             return
 
-        config = ConfigParser.RawConfigParser()
+        config = configparser.RawConfigParser()
 
         config.add_section("login")
@@ -892,15 +892,15 @@
         try:
             fd = os.open(configPath, os.O_CREAT|os.O_TRUNC|os.O_WRONLY,
-                         0600)
+                         0o600)
             with os.fdopen(fd, "wt") as f:
                 config.write(f)
             self._modified = False
 
-            print "Configuration saved:"
+            print("Configuration saved:")
             self.log()
 
-        except Exception, e:
-            print >> sys.stderr, "Failed to update config: " + \
-                                 utf2unicode(str(e))
+        except Exception as e:
+            print("Failed to update config: " + \
+                                 utf2unicode(str(e)), file=sys.stderr)
 
     def _getBoolean(self, config, section, option, default):
@@ -945,5 +945,5 @@
         import locale
         if self._language:
-            print "Setting up locale for", self._language
+            print("Setting up locale for", self._language)
             os.environ["LANGUAGE"] = self._language
             langAndEncoding = self._language + "." + locale.getpreferredencoding()
@@ -978,62 +978,62 @@
     def log(self):
         """Log the configuration by printing the values"""
-        print "  pilot ID:", self._pilotID
-        print "  rememberPassword:", self._rememberPassword
-
-        print "  language:", self._language
-
-        print "  hideMinimizedWindow:", self._hideMinimizedWindow
-        print "  quitOnClose:", self._quitOnClose
-
-        print "  onlineGateSystem:", self._onlineGateSystem
-        print "  onlineACARS:", self._onlineACARS
-
-        print "  flareTimeFromFS:", self._flareTimeFromFS
-        print "  syncFSTime:", self._syncFSTime
-        print "  usingFS2Crew:", self._usingFS2Crew
-
-        print "  iasSmoothingLength:", self._iasSmoothingLength
-        print "  vsSmoothingLength:", self._vsSmoothingLength
-
-        print "  useSimBrief:", self._useSimBrief
-        print "  simBriefUserName:", self._simBriefUserName
-        print "  rememberSimBriefPassword:", self._rememberSimBriefPassword
-
-        print "  pirepDirectory:", self._pirepDirectory
-        print "  pirepAutoSave:", self._pirepAutoSave
-
-        print "  defaultMSFS:", self._defaultMSFS
-
-        print "  enableSounds:", self._enableSounds
-
-        print "  pilotControlsSounds:", self._pilotControlsSounds
-        print "  pilotHotkey:", str(self._pilotHotkey)
-
-        print "  enableApproachCallouts:", self._enableApproachCallouts
-        print "  speedbrakeAtTD:", self._speedbrakeAtTD
-
-        print "  enableChecklists:", self._enableChecklists
-        print "  checklistHotkey:", str(self._checklistHotkey)
-
-        print "  autoUpdate:", self._autoUpdate
-        print "  updateURL:", self._updateURL
-        print "  useRPC:", self._useRPC
-
-        print "  messageTypeLevels:"
-        for (type, level) in self._messageTypeLevels.iteritems():
-            print "    %s: %s" % (const.messageType2string(type),
-                                  const.messageLevel2string(level))
-
-        print "  checklists:"
-        for (type, checklist) in self._checklists.iteritems():
-            print "    %s:" % (const.icaoCodes[type],)
+        print("  pilot ID:", self._pilotID)
+        print("  rememberPassword:", self._rememberPassword)
+
+        print("  language:", self._language)
+
+        print("  hideMinimizedWindow:", self._hideMinimizedWindow)
+        print("  quitOnClose:", self._quitOnClose)
+
+        print("  onlineGateSystem:", self._onlineGateSystem)
+        print("  onlineACARS:", self._onlineACARS)
+
+        print("  flareTimeFromFS:", self._flareTimeFromFS)
+        print("  syncFSTime:", self._syncFSTime)
+        print("  usingFS2Crew:", self._usingFS2Crew)
+
+        print("  iasSmoothingLength:", self._iasSmoothingLength)
+        print("  vsSmoothingLength:", self._vsSmoothingLength)
+
+        print("  useSimBrief:", self._useSimBrief)
+        print("  simBriefUserName:", self._simBriefUserName)
+        print("  rememberSimBriefPassword:", self._rememberSimBriefPassword)
+
+        print("  pirepDirectory:", self._pirepDirectory)
+        print("  pirepAutoSave:", self._pirepAutoSave)
+
+        print("  defaultMSFS:", self._defaultMSFS)
+
+        print("  enableSounds:", self._enableSounds)
+
+        print("  pilotControlsSounds:", self._pilotControlsSounds)
+        print("  pilotHotkey:", str(self._pilotHotkey))
+
+        print("  enableApproachCallouts:", self._enableApproachCallouts)
+        print("  speedbrakeAtTD:", self._speedbrakeAtTD)
+
+        print("  enableChecklists:", self._enableChecklists)
+        print("  checklistHotkey:", str(self._checklistHotkey))
+
+        print("  autoUpdate:", self._autoUpdate)
+        print("  updateURL:", self._updateURL)
+        print("  useRPC:", self._useRPC)
+
+        print("  messageTypeLevels:")
+        for (type, level) in self._messageTypeLevels.items():
+            print("    %s: %s" % (const.messageType2string(type),
+                                  const.messageLevel2string(level)))
+
+        print("  checklists:")
+        for (type, checklist) in self._checklists.items():
+            print("    %s:" % (const.icaoCodes[type],))
             for path in checklist:
-                print "      " + path
-
-        print "  approachCallouts:"
-        for (type, approachCallouts) in self._approachCallouts.iteritems():
-            print "    %s:" % (const.icaoCodes[type],)
+                print("      " + path)
+
+        print("  approachCallouts:")
+        for (type, approachCallouts) in self._approachCallouts.items():
+            print("    %s:" % (const.icaoCodes[type],))
             for (altitude, path) in approachCallouts:
-                print "      %d: %s" % (altitude, path)
+                print("      %d: %s" % (altitude, path))
 
 #-------------------------------------------------------------------------------
Index: src/mlx/const.py
===================================================================
--- src/mlx/const.py	(revision 911)
+++ src/mlx/const.py	(revision 941)
@@ -12,5 +12,5 @@
 
 ## The version of the program
-VERSION="0.39.6"
+VERSION="0.39.6-py3"
 
 #-------------------------------------------------------------------------------
@@ -193,5 +193,5 @@
 def aircraftType2Family(aircraftType):
     """Get the family for the given aircraft type."""
-    for (family, types) in aircraftFamily2Types.iteritems():
+    for (family, types) in aircraftFamily2Types.items():
         if aircraftType in types:
             return family
@@ -424,5 +424,5 @@
 def string2messageLevel(str):
     """Get the message level for the given string."""
-    for (value, s) in _messageLevelStrings.iteritems():
+    for (value, s) in _messageLevelStrings.items():
         if str==s:
             return value
Index: src/mlx/flight.py
===================================================================
--- src/mlx/flight.py	(revision 846)
+++ src/mlx/flight.py	(revision 919)
@@ -1,8 +1,8 @@
 
-from soundsched import SoundScheduler, ChecklistScheduler
-from checks import SpeedChecker
-
-import const
-import util
+from .soundsched import SoundScheduler, ChecklistScheduler
+from .checks import SpeedChecker
+
+from . import const
+from . import util
 import time
 
Index: src/mlx/fs.py
===================================================================
--- src/mlx/fs.py	(revision 909)
+++ src/mlx/fs.py	(revision 919)
@@ -1,10 +1,10 @@
 
-import const
-from sound import startSound
+from . import const
+from .sound import startSound
 
 import os
 
-import fsuipc
-import xplane
+from . import fsuipc
+from . import xplane
 
 import threading
@@ -36,13 +36,13 @@
         """Called when a connection has been established to the flight
         simulator of the given type."""
-        print "fs.ConnectionListener.connected, fsType:", fsType, ", descriptor:", descriptor
+        print("fs.ConnectionListener.connected, fsType:", fsType, ", descriptor:", descriptor)
 
     def connectionFailed(self):
         """Called when the connection could not be established."""
-        print "fs.ConnectionListener.connectionFailed"
+        print("fs.ConnectionListener.connectionFailed")
 
     def disconnected(self):
         """Called when a connection to the flight simulator has been broken."""
-        print "fs.ConnectionListener.disconnected"
+        print("fs.ConnectionListener.disconnected")
 
 #-------------------------------------------------------------------------------
Index: src/mlx/fsuipc.py
===================================================================
--- src/mlx/fsuipc.py	(revision 877)
+++ src/mlx/fsuipc.py	(revision 922)
@@ -1,8 +1,8 @@
 
-import fs
-import const
-import util
-import acft
-from watchdog import Watchdog
+from . import fs
+from . import const
+from . import util
+from . import acft
+from .watchdog import Watchdog
 
 import threading
@@ -13,9 +13,10 @@
 import codecs
 import math
+from functools import total_ordering
 
 if os.name == "nt" and "FORCE_PYUIPC_SIM" not in os.environ:
     import pyuipc
 else:
-    import pyuipc_sim as pyuipc
+    from . import pyuipc_sim as pyuipc
 
 #------------------------------------------------------------------------------
@@ -104,6 +105,6 @@
         try:
             return fun()
-        except Exception, e:
-            print >> sys.stderr, util.utf2unicode(str(e))
+        except Exception as e:
+            print(util.utf2unicode(str(e)), file=sys.stderr)
             return None
 
@@ -133,5 +134,5 @@
             try:
                 values = pyuipc.read(data)
-            except TypeError, e:
+            except TypeError as e:
                 exception = e
 
@@ -174,5 +175,5 @@
                 try:
                     pyuipc.write(self._data)
-                except TypeError, e:
+                except TypeError as e:
                     exception = e
 
@@ -197,4 +198,5 @@
                 Handler._callSafe(lambda: self._callback(None, self._extra))
 
+    @total_ordering
     class PeriodicRequest(object):
         """A periodic request."""
@@ -250,8 +252,15 @@
             pass
 
-        def __cmp__(self, other):
-            """Compare two periodic requests. They are ordered by their next
-            firing times."""
-            return cmp(self._nextFire, other._nextFire)
+        def __eq__(self, other):
+            """Equality comparison by the firing times"""
+            return self._nextFire == other._nextFire
+
+        def __ne__(self, other):
+            """Non-equality comparison by the firing times"""
+            return self._nextFire != other._nextFire
+
+        def __lt__(self, other):
+            """Less-than comparison by the firing times"""
+            return self._nextFire < other._nextFire
 
     def __init__(self, connectionListener,
@@ -420,8 +429,8 @@
                 self._connected = True
                 return attempts
-            except Exception, e:
-                print "fsuipc.Handler._connect: connection failed: " + \
+            except Exception as e:
+                print("fsuipc.Handler._connect: connection failed: " + \
                       util.utf2unicode(str(e)) + \
-                      " (attempts: %d)" % (attempts,)
+                      " (attempts: %d)" % (attempts,))
                 if attempts<self.NUM_CONNECTATTEMPTS:
                     time.sleep(self.CONNECT_INTERVAL)
@@ -454,5 +463,5 @@
     def _disconnect(self):
         """Disconnect from the flight simulator."""
-        print "fsuipc.Handler._disconnect"
+        print("fsuipc.Handler._disconnect")
         if self._connected:
             pyuipc.close()
@@ -479,16 +488,16 @@
             try:
                 if not request.process(time):
-                    print "fsuipc.Handler._processRequest: FSUIPC returned invalid data too many times, reconnecting"
+                    print("fsuipc.Handler._processRequest: FSUIPC returned invalid data too many times, reconnecting")
                     needReconnect = True
             except TypeError as e:
-                print "fsuipc.Handler._processRequest: type error: " + \
+                print("fsuipc.Handler._processRequest: type error: " + \
                       util.utf2unicode(str(e)) + \
                       ("." if request.unimportant else
-                       (", reconnecting (attempts=%d)." % (attempts,)))
+                       (", reconnecting (attempts=%d)." % (attempts,))))
                 needReconnect = not request.unimportant
             except Exception as e:
-                print "fsuipc.Handler._processRequest: FSUIPC connection failed (" + \
+                print("fsuipc.Handler._processRequest: FSUIPC connection failed (" + \
                       util.utf2unicode(str(e)) + \
-                      "), reconnecting (attempts=%d)." % (attempts,)
+                      "), reconnecting (attempts=%d)." % (attempts,))
                 needReconnect = True
 
@@ -723,5 +732,5 @@
         duration is the number of seconds to keep the message displayed."""
 
-        print "fsuipc.Simulator.sendMessage:", message
+        print("fsuipc.Simulator.sendMessage:", message)
 
         if self._scroll:
@@ -732,6 +741,6 @@
         try:
             message = str(message)
-        except Exception, e:
-            print "fsuipc.Simulator.sendMessage: failed to convert the message to a string:", e
+        except Exception as e:
+            print("fsuipc.Simulator.sendMessage: failed to convert the message to a string:", e)
 
         data = [(0x3380, -1 - len(message), message),
@@ -822,5 +831,5 @@
         assert not self._monitoringRequested
 
-        print "fsuipc.Simulator.disconnect", closingMessage, duration
+        print("fsuipc.Simulator.disconnect", closingMessage, duration)
 
         self._stopNormal()
@@ -953,6 +962,6 @@
             return False
 
-        print "fsuipc.Simulator: new aircraft name and air file path: %s, %s" % \
-              (name, airPath)
+        print("fsuipc.Simulator: new aircraft name and air file path: %s, %s" % \
+              (name, airPath))
 
         self._aircraftName = aircraftName
@@ -1088,10 +1097,11 @@
             self._handler.disconnect()
 
-    def _handleNumHotkeys(self, data, (id, generation)):
+    def _handleNumHotkeys(self, data, xxx_todo_changeme5):
         """Handle the result of the query of the number of hotkeys"""
+        (id, generation) = xxx_todo_changeme5
         with self._hotkeyLock:
             if id==self._hotkeySetID and generation==self._hotkeySetGeneration:
                 numHotkeys = data[0]
-                print "fsuipc.Simulator._handleNumHotkeys: numHotkeys:", numHotkeys
+                print("fsuipc.Simulator._handleNumHotkeys: numHotkeys:", numHotkeys)
                 data = [(0x3210 + i*4, "d") for i in range(0, numHotkeys)]
                 self._handler.requestRead(data, self._handleHotkeyTable,
@@ -1135,10 +1145,11 @@
 
         for offset in oldHotkeyOffsets:
-            writeData.append((offset, "u", long(0)))
+            writeData.append((offset, "u", int(0)))
 
         return writeData
 
-    def _handleHotkeyTable(self, data, (id, generation)):
+    def _handleHotkeyTable(self, data, xxx_todo_changeme6):
         """Handle the result of the query of the hotkey table."""
+        (id, generation) = xxx_todo_changeme6
         with self._hotkeyLock:
             if id==self._hotkeySetID and generation==self._hotkeySetGeneration:
@@ -1148,6 +1159,7 @@
                                            (id, generation))
 
-    def _handleHotkeysWritten(self, success, (id, generation)):
+    def _handleHotkeysWritten(self, success, xxx_todo_changeme7):
         """Handle the result of the hotkeys having been written."""
+        (id, generation) = xxx_todo_changeme7
         with self._hotkeyLock:
             if success and id==self._hotkeySetID and \
@@ -1160,6 +1172,7 @@
                                                       (id, generation))
 
-    def _handleHotkeys(self, data, (id, generation)):
+    def _handleHotkeys(self, data, xxx_todo_changeme8):
         """Handle the hotkeys."""
+        (id, generation) = xxx_todo_changeme8
         with self._hotkeyLock:
             if id!=self._hotkeySetID or generation!=self._hotkeySetGeneration:
@@ -1397,7 +1410,7 @@
 
         numNotchesM1 = len(self._flapsNotches) - 1
-        flapsIncrement = 16383 / numNotchesM1
+        flapsIncrement = 16383 // numNotchesM1
         flapsControl = data[self._monidx_flapsControl]
-        flapsIndex = flapsControl / flapsIncrement
+        flapsIndex = flapsControl // flapsIncrement
         if flapsIndex < numNotchesM1:
             if (flapsControl - (flapsIndex*flapsIncrement) >
@@ -1406,8 +1419,8 @@
         state.flapsSet = self._flapsNotches[flapsIndex]
         if state.flapsSet != self._flapsSet:
-            print "flapsControl: %d, flapsLeft: %d, flapsRight: %d, flapsAxis: %d, flapsIncrement: %d, flapsSet: %d, numNotchesM1: %d" % \
+            print("flapsControl: %d, flapsLeft: %d, flapsRight: %d, flapsAxis: %d, flapsIncrement: %d, flapsSet: %d, numNotchesM1: %d" % \
                   (flapsControl, data[self._monidx_flapsLeft],
                    data[self._monidx_flapsRight], data[self._monidx_flapsAxis],
-                   data[self._monidx_flapsIncrement], state.flapsSet, numNotchesM1)
+                   data[self._monidx_flapsIncrement], state.flapsSet, numNotchesM1))
             self._flapsSet = state.flapsSet
 
@@ -1588,5 +1601,5 @@
         for (tank, level) in levels:
             offset = _tank2offset[tank]
-            value = long(level * 128.0 * 65536.0)
+            value = int(level * 128.0 * 65536.0)
             data.append( (offset, "u", value) )
 
@@ -1698,7 +1711,8 @@
     """A model handler for the PMDG Boeing 737NG model."""
     @staticmethod
-    def doesHandle(aircraft, (name, airPath)):
+    def doesHandle(aircraft, xxx_todo_changeme):
         """Determine if this model handler handles the aircraft with the given
         name."""
+        (name, airPath) = xxx_todo_changeme
         return aircraft.type in [const.AIRCRAFT_B736,
                                  const.AIRCRAFT_B737,
@@ -1730,6 +1744,6 @@
 
         if fsType==const.SIM_MSFSX or fsType==const.SIM_P3D:
-            print "%s detected, adding PMDG 737 NGX-specific offsets" % \
-                  ("FSX" if fsType==const.SIM_MSFSX else "P3D",)
+            print("%s detected, adding PMDG 737 NGX-specific offsets" % \
+                  ("FSX" if fsType==const.SIM_MSFSX else "P3D",))
             self._addOffsetWithIndexMember(data, 0x6500, "b",
                                            "_pmdgidx_lts_positionsw")
@@ -1741,5 +1755,5 @@
             self._addOffsetWithIndexMember(data, 0x65cd, "b", "_pmdgidx_xpdr")
         else:
-            print "FS9 detected, adding PMDG 737 NG-specific offsets"
+            print("FS9 detected, adding PMDG 737 NG-specific offsets")
             self._addOffsetWithIndexMember(data, 0x6202, "b", "_pmdgidx_switches")
             self._addOffsetWithIndexMember(data, 0x6216, "b", "_pmdgidx_xpdr")
@@ -1786,5 +1800,5 @@
 
         if gearControl!=self._lastGearControl or noseGear!=self._lastNoseGear:
-            print "gearControl:", gearControl, " noseGear:", noseGear
+            print("gearControl:", gearControl, " noseGear:", noseGear)
             self._lastGearControl = gearControl
             self._lastNoseGear = noseGear
@@ -1833,7 +1847,8 @@
     """Model handler for the Dreamwings Dash 8-Q400."""
     @staticmethod
-    def doesHandle(aircraft, (name, airPath)):
+    def doesHandle(aircraft, xxx_todo_changeme1):
         """Determine if this model handler handles the aircraft with the given
         name."""
+        (name, airPath) = xxx_todo_changeme1
         return aircraft.type==const.AIRCRAFT_DH8D and \
             (name.find("Dreamwings")!=-1 or airPath.find("Dreamwings")!=-1) and \
@@ -1870,7 +1885,8 @@
     """Model handler for the Majestic Dash 8-Q400."""
     @staticmethod
-    def doesHandle(aircraft, (name, airPath)):
+    def doesHandle(aircraft, xxx_todo_changeme2):
         """Determine if this model handler handles the aircraft with the given
         name."""
+        (name, airPath) = xxx_todo_changeme2
         return aircraft.type==const.AIRCRAFT_DH8D and \
             (name.find("MJC8Q400")!=-1 or \
@@ -1948,7 +1964,8 @@
     """Model for the Digital Aviation F70 implementation on FS9."""
     @staticmethod
-    def doesHandle(aircraft, (name, airPath)):
+    def doesHandle(aircraft, xxx_todo_changeme3):
         """Determine if this model handler handles the aircraft with the given
         name."""
+        (name, airPath) = xxx_todo_changeme3
         return aircraft.type == const.AIRCRAFT_F70 and \
                (airPath.endswith("fokker70_2k4_v4.1.air") or
@@ -2137,8 +2154,9 @@
     """Project Tupolev Tu-154."""
     @staticmethod
-    def doesHandle(aircraft, (name, airPath)):
+    def doesHandle(aircraft, xxx_todo_changeme4):
         """Determine if this model handler handles the aircraft with the given
         name."""
-        print "PTT154Model.doesHandle", aircraft.type, name, airPath
+        (name, airPath) = xxx_todo_changeme4
+        print("PTT154Model.doesHandle", aircraft.type, name, airPath)
         return aircraft.type==const.AIRCRAFT_T154 and \
                (name.find("Tu-154")!=-1 or name.find("Tu154B")!=-1) and \
Index: src/mlx/gui/acars.py
===================================================================
--- src/mlx/gui/acars.py	(revision 747)
+++ src/mlx/gui/acars.py	(revision 919)
@@ -1,9 +1,9 @@
 
-from common import *
+from .common import *
 
 from mlx.i18n import xstr
 import mlx.const as const
 
-import cef
+from . import cef
 
 #------------------------------------------------------------------------------
Index: src/mlx/gui/bugreport.py
===================================================================
--- src/mlx/gui/bugreport.py	(revision 492)
+++ src/mlx/gui/bugreport.py	(revision 954)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 from mlx.i18n import xstr
@@ -105,5 +105,5 @@
         response = super(BugReportDialog, self).run()
 
-        print "response", response, RESPONSETYPE_ACCEPT
+        print("response", response, RESPONSETYPE_ACCEPT)
         if response==RESPONSETYPE_ACCEPT:
             self._send()
@@ -126,9 +126,8 @@
                                      descriptionBuffer.get_end_iter(),
                                      False)
-        description = text2unicode(description)
         self.set_sensitive(False)
-        self._gui.sendBugReport(text2unicode(self._summary.get_text()),
+        self._gui.sendBugReport(self._summary.get_text(),
                                 description,
-                                text2unicode(self._email.get_text()),
+                                self._email.get_text(),
                                 self._bugReportSent)
 
Index: src/mlx/gui/callouts.py
===================================================================
--- src/mlx/gui/callouts.py	(revision 300)
+++ src/mlx/gui/callouts.py	(revision 919)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 from mlx.i18n import xstr
@@ -208,5 +208,5 @@
             config = self._gui.config
             for (aircraftType, approachCallouts) in \
-                    self._approachCallouts.iteritems():
+                    self._approachCallouts.items():
                 config.setApproachCallouts(aircraftType, approachCallouts)
             config.save()
Index: src/mlx/gui/cef.py
===================================================================
--- src/mlx/gui/cef.py	(revision 915)
+++ src/mlx/gui/cef.py	(revision 945)
@@ -1,3 +1,3 @@
-from common import *
+from .common import *
 
 from mlx.util import secondaryInstallation
@@ -10,11 +10,12 @@
 import os
 import re
-import thread
+import _thread
 import threading
 import tempfile
 import traceback
-import urllib2
+import ctypes
+import urllib.request, urllib.error, urllib.parse
 from lxml import etree
-from StringIO import StringIO
+from io import StringIO
 import lxml.html
 
@@ -112,9 +113,9 @@
                              SIMBRIEF_RESULT_NONE, None)
 
-    def _onLoadEnd(self, browser, frame, httpCode):
+    def _onLoadEnd(self, browser, frame, http_code):
         """Called when a page has been loaded in the SimBrief browser."""
         url = frame.GetUrl()
-        print "gui.cef.SimBriefHandler._onLoadEnd", httpCode, url
-        if httpCode>=300:
+        print("gui.cef.SimBriefHandler._onLoadEnd", http_code, url)
+        if http_code>=300:
             self._updateProgress(self._lastProgress,
                                  SIMBRIEF_RESULT_ERROR_OTHER, None)
@@ -127,7 +128,7 @@
 
             js = "form=document.getElementById(\"sbapiform\");"
-            for (name, value) in self._plan.iteritems():
+            for (name, value) in self._plan.items():
                 js += "form." + name + ".value=\"" + value + "\";"
-            for (name, value) in SimBriefHandler._querySettings.iteritems():
+            for (name, value) in SimBriefHandler._querySettings.items():
                 if isinstance(value, bool):
                     js += "form." + name + ".checked=" + \
@@ -175,6 +176,6 @@
 
             thread = threading.Thread(target = self._getResults, args = (link,))
-            thread.daemon = True
-            thread.start()
+            _thread.daemon = True
+            _thread.start()
         else:
             self._updateProgress(SIMBRIEF_PROGRESS_RETRIEVING_BRIEFING,
@@ -194,8 +195,10 @@
         self._lastProgress = progress
         if results!=SIMBRIEF_RESULT_NONE:
-            gobject.source_remove(self._timeoutID)
+            if self._timeoutID is not None:
+                gobject.source_remove(self._timeoutID)
             self._plan = None
 
-        self._updateProgressFn(progress, results, flightInfo)
+        if self._updateProgressFn is not None:
+            self._updateProgressFn(progress, results, flightInfo)
 
     def _timedOut(self):
@@ -219,5 +222,5 @@
 
         # Obtaining the xml
-        response = urllib2.urlopen(link)
+        response = urllib.request.urlopen(link)
         xmlContent = response.read()
         # Processing xml
@@ -242,5 +245,5 @@
                     imageLinks.append(imageLink[2])
         flightInfo["image_links"] = imageLinks
-        print(sorted(availableInfo.keys()))
+        print((sorted(availableInfo.keys())))
         htmlFilePath = "simbrief_plan.html" if self._htmlFilePath is None \
           else self._htmlFilePath
@@ -266,5 +269,5 @@
 def _initializeCEF(args, initializedCallback):
     """Perform the actual initialization of CEF using the given arguments."""
-    print "Initializing CEF with args:", args
+    print("Initializing CEF with args:", args)
 
     settings = {
@@ -290,5 +293,5 @@
                     switches[arg[2:assignIndex]] = arg[assignIndex+1:]
         else:
-            print "Unhandled switch", arg
+            print("Unhandled switch", arg)
 
     cefpython.Initialize(settings, switches)
@@ -296,5 +299,5 @@
     gobject.timeout_add(10, _handleTimeout)
 
-    print "Initialized, executing callback..."
+    print("Initialized, executing callback...")
     initializedCallback()
 
@@ -320,12 +323,17 @@
     """Start a browser instance in the given container with the given URL."""
     if os.name=="nt":
-        window = container.get_window()
-        if window is None:
-            print "mlx.gui.cef.startInContainer: no window found!"
-            windowID = None
-        else:
-            windowID = window.handle
+        gdk.threads_enter()
+        ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
+        ctypes.pythonapi.PyCapsule_GetPointer.argtypes = \
+            [ctypes.py_object]
+        gpointer = ctypes.pythonapi.PyCapsule_GetPointer(
+            container.get_property("window").__gpointer__, None)
+        libgdk = ctypes.CDLL("libgdk-3-0.dll")
+        windowID = libgdk.gdk_win32_window_get_handle(gpointer)
+        container.windowID = windowID
+        gdk.threads_leave()
     else:
-        windowID = container.window.xid
+        container.set_visual(container.get_screen().lookup_visual(0x21))
+        windowID = container.get_window().get_xid()
 
     windowInfo = cefpython.WindowInfo()
@@ -340,12 +348,12 @@
 
 class OffscreenRenderHandler(object):
-    def GetRootScreenRect(self, browser, rect):
+    def GetRootScreenRect(self, browser, rect_out):
         #print "GetRootScreenRect"
-        rect += [0, 0, 800, 600]
+        rect_out += [0, 0, 800, 600]
         return True
 
-    def GetViewRect(self, browser, rect):
+    def GetViewRect(self, browser, rect_out):
         #print "GetViewRect"
-        rect += [0, 0, 800, 600]
+        rect_out += [0, 0, 800, 600]
         return True
 
@@ -367,5 +375,5 @@
         pass
 
-    def OnPaint(self, browser, paintElementType, dirtyRects, buffer, width, height):
+    def OnPaint(self, browser, element_type, dirty_rects, paint_buffer, width, height):
         #print "OnPaint", paintElementType, dirtyRects, buffer, width, height
         pass
@@ -424,6 +432,5 @@
 
 def _handleSizeAllocate(widget, sizeAlloc):
-    """Handle the size-allocate event."""
-    window = widget.get_window()
+    """Handle the size-allocate event on Windows."""
     if widget is not None:
-        cefpython.WindowUtils.OnSize(window.handle, 0, 0, 0)
+        cefpython.WindowUtils.OnSize(widget.windowID, 0, 0, 0)
Index: src/mlx/gui/checklist.py
===================================================================
--- src/mlx/gui/checklist.py	(revision 300)
+++ src/mlx/gui/checklist.py	(revision 954)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 from mlx.i18n import xstr
@@ -190,5 +190,5 @@
             self._saveChecklist()
             config = self._gui.config
-            for (aircraftType, checklist) in self._checklists.iteritems():
+            for (aircraftType, checklist) in self._checklists.items():
                 config.setChecklist(aircraftType, checklist)
             config.save()
@@ -204,5 +204,4 @@
         numSelected = 0
         for path in fileChooser.get_filenames():
-            path = text2unicode(path)
             numSelected += 1
             if os.path.isfile(path): numFiles += 1
@@ -213,5 +212,4 @@
         """Called when the Add button is clicked."""
         for path in self._fileChooser.get_filenames():
-            path = text2unicode(path)
             self._fileListModel.append([os.path.basename(path),
                                         path])
Index: src/mlx/gui/common.py
===================================================================
--- src/mlx/gui/common.py	(revision 863)
+++ src/mlx/gui/common.py	(revision 954)
@@ -31,5 +31,5 @@
 
 if not pygobject:
-    print "Using PyGTK"
+    print("Using PyGTK")
     pygobject = False
     import pygtk
@@ -42,5 +42,5 @@
         import appindicator
         appIndicator = True
-    except Exception, e:
+    except Exception as e:
         pass
 
@@ -111,20 +111,19 @@
     pixbuf_new_from_file = gdk.pixbuf_new_from_file
 
-    def text2unicode(text):
-        """Convert the given text, returned by a Gtk widget, to Unicode."""
-        return unicode(text)
-
-    def text2str(text):
-        """Convert the given text, returned by xstr to a string."""
-        return str(text)
-
 else: # pygobject
+    import gi
+    gi.require_version("Gdk", "3.0")
     from gi.repository import Gdk as gdk
     from gi.repository import GdkPixbuf as gdkPixbuf
+    gi.require_version("Gtk", "3.0")
     from gi.repository import Gtk as gtk
-    from gi.repository import AppIndicator3 as appindicator
+    try:
+        gi.require_version("AppIndicator3", "0.1")
+        from gi.repository import AppIndicator3 as appindicator
+        appIndicator = True
+    except:
+        pass
     from gi.repository import Pango as pango
 
-    appIndicator = True
 
 
@@ -193,12 +192,4 @@
     _utf8Decoder = codecs.getdecoder("utf-8")
 
-    def text2unicode(str):
-        """Convert the given text, returned by a Gtk widget, to Unicode."""
-        return _utf8Decoder(str)[0]
-
-    def text2str(text):
-        """Convert the given text, returned by xstr to a string."""
-        return _utf8Decoder(text)[0]
-
 import cairo
 
@@ -296,5 +287,6 @@
     def __init__(self):
         """Construct the entry"""
-        super(TimeEntry, self).__init__(max = 5)
+        super(TimeEntry, self).__init__()
+        self.set_max_width_chars(5)
 
         self.connect("insert-text", self._insertText)
Index: src/mlx/gui/delaycodes.py
===================================================================
--- src/mlx/gui/delaycodes.py	(revision 840)
+++ src/mlx/gui/delaycodes.py	(revision 919)
@@ -3,5 +3,5 @@
 #------------------------------------------------------------------------------
 
-from dcdata import CAPTION, DELAYCODE, getTable
+from .dcdata import CAPTION, DELAYCODE, getTable
 
 from mlx.gui.common import *
Index: src/mlx/gui/faultexplain.py
===================================================================
--- src/mlx/gui/faultexplain.py	(revision 842)
+++ src/mlx/gui/faultexplain.py	(revision 919)
@@ -247,5 +247,5 @@
     def reset(self):
         """Reset the widget by removing all faults."""
-        for (alignment, faultFrame) in self._faultWidgets.itervalues():
+        for (alignment, faultFrame) in self._faultWidgets.values():
             self._faults.remove(alignment)
         self._faults.show_all()
Index: src/mlx/gui/flight.py
===================================================================
--- src/mlx/gui/flight.py	(revision 872)
+++ src/mlx/gui/flight.py	(revision 954)
@@ -405,10 +405,10 @@
     def _offlineClicked(self, button):
         """Called when the offline button was clicked."""
-        print "mlx.flight.LoginPage: offline flight selected"
+        print("mlx.flight.LoginPage: offline flight selected")
         self._wizard.nextPage()
 
     def _loginClicked(self, button):
         """Called when the login button was clicked."""
-        print "mlx.flight.LoginPage: logging in"
+        print("mlx.flight.LoginPage: logging in")
         self._wizard.login(self._handleLoginResult,
                            self._pilotID.get_text(),
@@ -648,11 +648,11 @@
 
         if response==RESPONSETYPE_OK:
-            fileName = text2unicode(dialog.get_filename())
-            print "Saving", fileName
+            fileName = dialog.get_filename()
+            print("Saving", fileName)
             try:
                 with open(fileName, "wt") as f:
                     flight.writeIntoFile(f)
-            except Exception, e:
-                print "Failed to save flight:", util.utf2unicode(str(e))
+            except Exception as e:
+                print("Failed to save flight:", util.utf2unicode(str(e)))
                 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
                                            type = MESSAGETYPE_ERROR,
@@ -706,5 +706,5 @@
         flight=self._getSelectedFlight()
 
-        print "DPI", context.get_dpi_x(), context.get_dpi_y()
+        print("DPI", context.get_dpi_x(), context.get_dpi_y())
 
         scale = context.get_dpi_x() / 72.0
@@ -719,5 +719,5 @@
 
         layout = cr.create_layout()
-        layout.set_text(u"Malév VA official briefing")
+        layout.set_text("Malév VA official briefing")
         font = pango.FontDescription("sans")
         font.set_size(int(32 * scale * pango.SCALE))
@@ -740,5 +740,5 @@
 
         layout = cr.create_layout()
-        layout.set_text(u"%s (%s) részére" %
+        layout.set_text("%s (%s) részére" %
                         (loginResult.pilotName, loginResult.pilotID))
         font = pango.FontDescription("sans")
@@ -939,6 +939,6 @@
 
         if response==RESPONSETYPE_OK:
-            fileName = text2unicode(dialog.get_filename())
-            print "Loading", fileName
+            fileName = dialog.get_filename()
+            print("Loading", fileName)
             bookedFlight = web.BookedFlight()
             try:
@@ -946,6 +946,6 @@
                     bookedFlight.readFromFile(f)
                 self.addFlight(bookedFlight)
-            except Exception, e:
-                print "Failed to load flight:", util.utf2unicode(str(e))
+            except Exception as e:
+                print("Failed to load flight:", util.utf2unicode(str(e)))
                 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
                                            type = MESSAGETYPE_ERROR,
@@ -1629,13 +1629,13 @@
                                             self.phoneNumber, self.nationality,
                                             self.password)
-        print "Registering with data:"
-        print "  name:", self.name1, self.name2, registrationData.firstName, registrationData.surName, requestedNameOrder
-        print "  yearOfBirth:", self.yearOfBirth, registrationData.yearOfBirth
-        print "  emailAddress:", self.emailAddress, registrationData.emailAddress
-        print "  emailAddressPublic:", self.emailAddressPublic, registrationData.emailAddressPublic
-        print "  vatsimID:", self.vatsimID, registrationData.vatsimID
-        print "  ivaoID:", self.ivaoID, registrationData.ivaoID
-        print "  phoneNumber:", self.phoneNumber, registrationData.phoneNumber
-        print "  nationality:", self.nationality, registrationData.nationality
+        print("Registering with data:")
+        print("  name:", self.name1, self.name2, registrationData.firstName, registrationData.surName, requestedNameOrder)
+        print("  yearOfBirth:", self.yearOfBirth, registrationData.yearOfBirth)
+        print("  emailAddress:", self.emailAddress, registrationData.emailAddress)
+        print("  emailAddressPublic:", self.emailAddressPublic, registrationData.emailAddressPublic)
+        print("  vatsimID:", self.vatsimID, registrationData.vatsimID)
+        print("  ivaoID:", self.ivaoID, registrationData.ivaoID)
+        print("  phoneNumber:", self.phoneNumber, registrationData.phoneNumber)
+        print("  nationality:", self.nationality, registrationData.nationality)
 
         gui = self._wizard.gui
@@ -1653,13 +1653,13 @@
         gui.endBusy()
 
-        print "Registration result:"
-        print "  returned:", returned
+        print("Registration result:")
+        print("  returned:", returned)
         if returned:
-            print "  registered:", result.registered
+            print("  registered:", result.registered)
             if result.registered:
-                print "  pilotID", result.pilotID
-                print "  loggedIn", result.loggedIn
-            print "  emailAlreadyRegistered:", result.emailAlreadyRegistered
-            print "  invalidData:", result.invalidData
+                print("  pilotID", result.pilotID)
+                print("  loggedIn", result.loggedIn)
+            print("  emailAlreadyRegistered:", result.emailAlreadyRegistered)
+            print("  invalidData:", result.invalidData)
 
         registrationOK = returned and result.registered
@@ -1830,5 +1830,5 @@
     def activate(self):
         """Activate the student page."""
-        print "StudentPage.activate"
+        print("StudentPage.activate")
         self._getEntryExamStatusCancelled = False
 
@@ -1844,5 +1844,5 @@
     def finalize(self):
         """Finalize the page."""
-        print "StudentPage.finalize"
+        print("StudentPage.finalize")
         self._getEntryExamStatusCancelled = True
 
@@ -1864,5 +1864,5 @@
     def _handleEntryExamStatus(self, returned, result):
         """Called when the entry exam status is availabe."""
-        print "_handleEntryExamStatus", returned, result
+        print("_handleEntryExamStatus", returned, result)
         if returned and not self._getEntryExamStatusCancelled:
             self._entryExamLink = result.entryExamLink
@@ -2991,5 +2991,5 @@
 
             plan = self._getPlan()
-            print "plan:", plan
+            print("plan:", plan)
 
             takeoffRunway = self._takeoffRunway.get_text()
@@ -3027,5 +3027,5 @@
         are returned. Otherwise a dialog box is displayed informing the user of
         invalid credentials and requesting another set of them."""
-        print "_getCredentials", count
+        print("_getCredentials", count)
         if count==0:
             return (self._userName.get_text(), self._password.get_text())
@@ -3061,5 +3061,5 @@
     def _simBriefProgress(self, progress, result, flightInfo):
         """The real SimBrief progress handler."""
-        print "_simBriefProgress", progress, result, flightInfo
+        print("_simBriefProgress", progress, result, flightInfo)
         if result==cef.SIMBRIEF_RESULT_NONE:
             message = SimBriefSetupPage.progress2Message.get(progress,
@@ -3758,5 +3758,5 @@
     def _metarChanged(self, buffer):
         """Called when the METAR has changed."""
-        print "BriefingPage.metarChanged", self._updatingMETAR
+        print("BriefingPage.metarChanged", self._updatingMETAR)
         if not self._updatingMETAR:
             self.metarEdited = True
@@ -3770,5 +3770,5 @@
 
         It uppercases all characters."""
-        print "BriefingPage.metarInserted", self._updatingMETAR
+        print("BriefingPage.metarInserted", self._updatingMETAR)
         if not self._updatingMETAR:
             self._updatingMETAR = True
@@ -4025,5 +4025,5 @@
     def activate(self):
         """Activate the page."""
-        print "TakeoffPage.activate"
+        print("TakeoffPage.activate")
 
         self._updatingMETAR = True
@@ -4069,5 +4069,5 @@
     def allowForward(self):
         """Allow going to the next page."""
-        print "TakeoffPage.allowForward"
+        print("TakeoffPage.allowForward")
         self._forwardAllowed = True
         self._updateForwardButton()
@@ -4075,5 +4075,5 @@
     def reset(self):
         """Reset the page if the wizard is reset."""
-        print "TakeoffPage.reset"
+        print("TakeoffPage.reset")
 
         super(TakeoffPage, self).reset()
@@ -4095,5 +4095,5 @@
         pages."""
         if self._active:
-            print "TakeoffPage.changeMETAR"
+            print("TakeoffPage.changeMETAR")
             self._updatingMETAR = True
             self._metar.get_buffer().set_text(metar, -1)
@@ -4116,14 +4116,14 @@
                      self.derate is not None)
 
-        print "TakeoffPage._updateForwardButton: forwardAllowed:", self._forwardAllowed, ", sensitive:", sensitive
+        print("TakeoffPage._updateForwardButton: forwardAllowed:", self._forwardAllowed, ", sensitive:", sensitive)
         if self._forwardAllowed:
-            print "  METAR: ", self._metar.get_text()
-            print "  runway: ", self._runway.get_text()
-            print "  SID:", self.sid
-            print "  V1:", self.v1
-            print "  VR:", self.vr
-            print "  V2:", self.v2
-            print "  derateType:", self._derateType
-            print "  derate:", self.derate
+            print("  METAR: ", self._metar.get_text())
+            print("  runway: ", self._runway.get_text())
+            print("  SID:", self.sid)
+            print("  V1:", self.v1)
+            print("  VR:", self.vr)
+            print("  V2:", self.v2)
+            print("  derateType:", self._derateType)
+            print("  derate:", self.derate)
 
         self._button.set_sensitive(sensitive)
@@ -4131,5 +4131,5 @@
     def _valueChanged(self, widget, arg = None):
         """Called when the value of some widget has changed."""
-        print "TakeoffPage._valueChanged"
+        print("TakeoffPage._valueChanged")
 
         self._updateForwardButton()
@@ -4138,5 +4138,5 @@
         """Called when the value of some entry widget has changed and the value
         should be converted to uppercase."""
-        print "TakeoffPage._upperChanged"
+        print("TakeoffPage._upperChanged")
         entry.set_text(entry.get_text().upper())
         self._valueChanged(entry, arg)
@@ -4151,5 +4151,5 @@
     def _derateChanged(self, entry):
         """Called when the value of the derate is changed."""
-        print "TakeoffPage._derateChanged"
+        print("TakeoffPage._derateChanged")
         self._updateForwardButton()
 
@@ -4262,5 +4262,5 @@
     def _metarChanged(self, entry):
         """Called when the METAR has changed."""
-        print "TakeoffPage.metarChanged", self._updatingMETAR
+        print("TakeoffPage.metarChanged", self._updatingMETAR)
         if not self._updatingMETAR:
             self._updateForwardButton()
@@ -4271,5 +4271,5 @@
 
         It uppercases all characters."""
-        print "TakeoffPage.metarInserted", self._updatingMETAR
+        print("TakeoffPage.metarInserted", self._updatingMETAR)
         if not self._updatingMETAR:
             self._updatingMETAR = True
@@ -4628,5 +4628,5 @@
         pages."""
         if self._active:
-            print "LandingPage.changeMETAR"
+            print("LandingPage.changeMETAR")
             self._updatingMETAR = True
             self._metar.get_buffer().set_text(metar, -1)
@@ -4689,5 +4689,5 @@
     def _metarChanged(self, entry):
         """Called when the METAR has changed."""
-        print "LandingPage.metarChanged", self._updatingMETAR
+        print("LandingPage.metarChanged", self._updatingMETAR)
         if not self._updatingMETAR:
             self._updateForwardButton()
@@ -4698,5 +4698,5 @@
 
         It uppercases all characters."""
-        print "LandingPage.metarInserted", self._updatingMETAR
+        print("LandingPage.metarInserted", self._updatingMETAR)
         if not self._updatingMETAR:
             self._updatingMETAR = True
@@ -4740,5 +4740,5 @@
         self._lastSavePath = os.path.join(self._wizard.gui.config.pirepDirectory,
                                           self._getDefaultPIREPName())
-        self._lastSavePath = text2unicode(self._lastSavePath)
+        self._lastSavePath = self._lastSavePath
         self._savePIREP(page, automatic = True)
 
@@ -4777,5 +4777,5 @@
 
         if result==RESPONSETYPE_OK:
-            self._lastSavePath = text2unicode(dialog.get_filename())
+            self._lastSavePath = dialog.get_filename()
             self._savePIREP(page)
 
@@ -4797,5 +4797,5 @@
             type = MESSAGETYPE_ERROR
             message = xstr("finish_save_failed")
-            secondary = xstr("finish_save_failed_sec") % (text2unicode(error),)
+            secondary = xstr("finish_save_failed_sec") % (error,)
         else:
             type = MESSAGETYPE_INFO
@@ -5217,7 +5217,8 @@
         pass
 
-    def _formatTime(self, scheduledTime, realTimestamp, (warning, error)):
+    def _formatTime(self, scheduledTime, realTimestamp, xxx_todo_changeme):
         """Format the departure or arrival time based on the given data as a
         markup for a label."""
+        (warning, error) = xxx_todo_changeme
         realTime = time.gmtime(realTimestamp)
 
@@ -5752,5 +5753,5 @@
         elif stage==const.STAGE_LANDING:
             if not self._arrivalBriefingPage.metarEdited:
-                print "Downloading arrival METAR again"
+                print("Downloading arrival METAR again")
                 self.gui.webHandler.getMETARs(self._arrivalMETARCallback,
                                               [self._bookedFlight.arrivalICAO])
Index: src/mlx/gui/flightlist.py
===================================================================
--- src/mlx/gui/flightlist.py	(revision 868)
+++ src/mlx/gui/flightlist.py	(revision 927)
@@ -61,5 +61,5 @@
 
         if self._extraColumnAttributes is not None:
-            for (key, value) in self._extraColumnAttributes.iteritems():
+            for (key, value) in self._extraColumnAttributes.items():
                 if key=="alignment":
                     self._renderer.set_alignment(value, 0.5)
@@ -171,5 +171,5 @@
     def hasFlights(self):
         """Determine if there are any flights in the list."""
-        return self._model.get_iter_root() is not None
+        return self._model.get_iter_first() is not None
 
     def clear(self):
@@ -271,5 +271,6 @@
     def __init__(self, which, wizard, window, pirepEditable = False):
         """Construct the frame with the given title."""
-        super(PendingFlightsFrame, self).__init__(xstr("pendflt_title_" + which))
+        super(PendingFlightsFrame, self).__init__()
+        self.set_label(xstr("pendflt_title_" + which))
 
         self._which = which
@@ -401,5 +402,5 @@
         gui.endBusy()
 
-        print "PendingFlightsFrame._handleReflyResult", returned, result
+        print("PendingFlightsFrame._handleReflyResult", returned, result)
 
         if returned:
@@ -444,5 +445,5 @@
         gui.endBusy()
 
-        print "PendingFlightsFrame._handleDeleteResult", returned, result
+        print("PendingFlightsFrame._handleDeleteResult", returned, result)
 
         if returned:
Index: src/mlx/gui/gates.py
===================================================================
--- src/mlx/gui/gates.py	(revision 619)
+++ src/mlx/gui/gates.py	(revision 919)
@@ -143,5 +143,5 @@
         self._fleetStore.clear()
         if fleet is None:
-            for (gateNumber, label) in self._gateLabels.iteritems():
+            for (gateNumber, label) in self._gateLabels.items():
                 label.set_markup("<b>" + gateNumber + "</b>")
         else:        
Index: src/mlx/gui/gui.py
===================================================================
--- src/mlx/gui/gui.py	(revision 951)
+++ src/mlx/gui/gui.py	(revision 954)
@@ -1,8 +1,8 @@
 # -*- coding: utf-8 -*-
 
-from statusicon import StatusIcon
-from statusbar import Statusbar
-from info import FlightInfo
-from update import Updater
+from .statusicon import StatusIcon
+from .statusbar import Statusbar
+from .info import FlightInfo
+from .update import Updater
 from mlx.gui.common import *
 from mlx.gui.flight import Wizard
@@ -18,5 +18,5 @@
 from mlx.gui.acars import ACARS
 from mlx.gui.timetable import TimetableWindow
-import cef
+from . import cef
 
 import mlx.const as const
@@ -51,13 +51,13 @@
 class GUI(fs.ConnectionListener):
     """The main GUI class."""
-    _authors = [ (u"Váradi", u"István", "prog_test"),
-                 (u"Galyassy", u"Tamás", "negotiation"),
-                 (u"Kurják", u"Ákos", "test"),
-                 (u"Nagy", u"Dániel", "test"),
-                 (u"Radó", u"Iván", "test"),
-                 (u"Petrovszki", u"Gábor", "test"),
-                 (u"Serfőző", u"Tamás", "test"),
-                 (u"Szebenyi", u"Bálint", "test"),
-                 (u"Zsebényi-Loksa", u"Gergely", "test") ]
+    _authors = [ ("Váradi", "István", "prog_test"),
+                 ("Galyassy", "Tamás", "negotiation"),
+                 ("Kurják", "Ákos", "test"),
+                 ("Nagy", "Dániel", "test"),
+                 ("Radó", "Iván", "test"),
+                 ("Petrovszki", "Gábor", "test"),
+                 ("Serfőző", "Tamás", "test"),
+                 ("Szebenyi", "Bálint", "test"),
+                 ("Zsebényi-Loksa", "Gergely", "test") ]
 
     def __init__(self, programDirectory, config):
@@ -109,4 +109,6 @@
 
         self._mainWindow = window = gtk.Window()
+        if os.name!="nt":
+            window.set_visual(window.get_screen().lookup_visual(0x21))
         window.set_title(WINDOW_TITLE_BASE)
         window.set_icon_from_file(os.path.join(iconDirectory, "logo.ico"))
@@ -197,6 +199,4 @@
 
         window.show_all()
-        if os.name=="nt":
-            window.get_window().focus()
 
         self._wizard.grabDefault()
@@ -763,5 +763,5 @@
         Here we reset the focus to the main window as CEF might have acquired
         it earlier."""
-        self._mainWindow.get_window().focus()
+        self._mainWindow.get_window().focus(0)
 
     def raiseCallback(self):
@@ -1460,5 +1460,5 @@
                 secondaryMarkup = xstr("sendPIREP_unknown_sec")
         else:
-            print "PIREP sending failed", result
+            print("PIREP sending failed", result)
             messageFormat = xstr("sendPIREP_failed")
             secondaryMarkup = xstr("sendPIREP_failed_sec")
@@ -1492,5 +1492,5 @@
 
         if result==RESPONSETYPE_OK:
-            self._lastLoadedPIREP = text2unicode(dialog.get_filename())
+            self._lastLoadedPIREP = dialog.get_filename()
 
             pirep = PIREP.load(self._lastLoadedPIREP)
@@ -1684,5 +1684,5 @@
                 secondaryMarkup = xstr("sendPIREP_unknown_sec")
         else:
-            print "PIREP sending failed", result
+            print("PIREP sending failed", result)
             messageFormat = xstr("sendPIREP_failed")
             secondaryMarkup = xstr("sendPIREP_failed_sec")
@@ -1709,5 +1709,5 @@
 
         for (timestampString, text) in self._logger.lines:
-            description += unicode(formatFlightLogLine(timestampString, text))
+            description += str(formatFlightLogLine(timestampString, text))
 
         description += "\n\n" + ("=" * 40)
@@ -1796,11 +1796,11 @@
             for index in hotkeys:
                 if index==self._pilotHotkeyIndex:
-                    print "gui.GUI._handleHotkeys: pilot hotkey pressed"
+                    print("gui.GUI._handleHotkeys: pilot hotkey pressed")
                     self._flight.pilotHotkeyPressed()
                 elif index==self._checklistHotkeyIndex:
-                    print "gui.GUI._handleHotkeys: checklist hotkey pressed"
+                    print("gui.GUI._handleHotkeys: checklist hotkey pressed")
                     self._flight.checklistHotkeyPressed()
                 else:
-                    print "gui.GUI._handleHotkeys: unhandled hotkey index:", index
+                    print("gui.GUI._handleHotkeys: unhandled hotkey index:", index)
 
     def _showManual(self, menuitem):
Index: src/mlx/gui/info.py
===================================================================
--- src/mlx/gui/info.py	(revision 846)
+++ src/mlx/gui/info.py	(revision 954)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 from mlx.gui.delaycodes import DelayCodeTable
@@ -108,6 +108,6 @@
         """Get the comments."""
         buffer = self._comments.get_buffer()
-        return text2unicode(buffer.get_text(buffer.get_start_iter(),
-                                            buffer.get_end_iter(), True))
+        return buffer.get_text(buffer.get_start_iter(),
+                               buffer.get_end_iter(), True)
 
     @comments.setter
Index: src/mlx/gui/pirep.py
===================================================================
--- src/mlx/gui/pirep.py	(revision 855)
+++ src/mlx/gui/pirep.py	(revision 919)
@@ -1,7 +1,7 @@
 
-from common import *
-from dcdata import getTable
-from info import FlightInfo
-from flight import comboModel
+from .common import *
+from .dcdata import getTable
+from .info import FlightInfo
+from .flight import comboModel
 
 from mlx.pirep import PIREP
Index: src/mlx/gui/prefs.py
===================================================================
--- src/mlx/gui/prefs.py	(revision 738)
+++ src/mlx/gui/prefs.py	(revision 954)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 from mlx.i18n import xstr
@@ -6,5 +6,5 @@
 import mlx.config as config
 
-import urlparse
+import urllib.parse
 
 #------------------------------------------------------------------------------
@@ -63,5 +63,5 @@
 
         self._hotkeyModel = gtk.ListStore(str)
-        for keyCode in range(ord("0"), ord("9")+1) + range(ord("A"), ord("Z")+1):
+        for keyCode in list(range(ord("0"), ord("9")+1)) + list(range(ord("A"), ord("Z")+1)):
             self._hotkeyModel.append([chr(keyCode)])
 
@@ -296,5 +296,5 @@
                                                        self._vsSmoothingLength)
         config.useSimBrief = self._useSimBrief.get_active()
-        config.pirepDirectory = text2unicode(self._pirepDirectory.get_text())
+        config.pirepDirectory = self._pirepDirectory.get_text()
         config.pirepAutoSave = self._pirepAutoSave.get_active()
 
@@ -565,5 +565,5 @@
 
         if result==RESPONSETYPE_OK:
-            self._pirepDirectory.set_text(text2unicode(dialog.get_filename()))
+            self._pirepDirectory.set_text(dialog.get_filename())
 
     def _pirepDirectoryChanged(self, entry):
@@ -829,5 +829,5 @@
         sensitive = False
         try:
-            result = urlparse.urlparse(self._updateURL.get_text())
+            result = urllib.parse.urlparse(self._updateURL.get_text())
             sensitive = result.scheme!="" and (result.netloc + result.path)!=""
         except:
Index: src/mlx/gui/statusbar.py
===================================================================
--- src/mlx/gui/statusbar.py	(revision 679)
+++ src/mlx/gui/statusbar.py	(revision 919)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 import mlx.const as const
Index: src/mlx/gui/statusicon.py
===================================================================
--- src/mlx/gui/statusicon.py	(revision 544)
+++ src/mlx/gui/statusicon.py	(revision 919)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 import mlx.const as const
@@ -154,5 +154,5 @@
     def _updateFlightStatus(self):
         """Update the flight status."""
-        stage = u"-" if self._stage is None \
+        stage = "-" if self._stage is None \
                 else xstr("flight_stage_" + const.stage2string(self._stage))
 
@@ -172,5 +172,5 @@
             if self._noGoReason is not None:
                 rating = '<span foreground="red">' + rating + '</span>'
-            markup = u"MAVA Logger X %s\n\n%s: %s\n%s: %s" %\
+            markup = "MAVA Logger X %s\n\n%s: %s\n%s: %s" %\
                      (const.VERSION, xstr("statusicon_stage"), stage,
                       xstr("statusicon_rating"), rating)
Index: src/mlx/gui/timetable.py
===================================================================
--- src/mlx/gui/timetable.py	(revision 879)
+++ src/mlx/gui/timetable.py	(revision 927)
@@ -4,5 +4,5 @@
 
 from mlx.gui.common import *
-from flightlist import ColumnDescriptor
+from .flightlist import ColumnDescriptor
 from mlx.rpc import ScheduledFlight
 
@@ -82,6 +82,4 @@
         self._view = gtk.TreeView(self._model)
 
-        self._tooltips = gtk.Tooltips()
-        self._tooltips.disable()
         self._view.connect("motion-notify-event", self._updateTooltip)
 
@@ -225,6 +223,5 @@
             result = widget.get_path_at_pos( int(event.x), int(event.y))
             if result is None:
-                self._tooltips.set_tip(widget, "")
-                self._tooltips.disable()
+                widget.set_tooltip_text("")
             else:
                 (path, col, x, y) = result
@@ -244,13 +241,18 @@
                         text += date.strftime("%Y-%m-%d")
 
-                    self._tooltips.set_tip(widget, text)
-                    self._tooltips.enable()
+                    widget.set_tooltip_text(text)
                 else:
-                    self._tooltips.set_tip(widget, "")
-                    self._tooltips.disable()
-        except Exception, e:
-            print e
-            self._tooltips.set_tip(widget, "")
-            self._tooltips.disable()
+                    widget.set_tooltip_text("")
+        except Exception as e:
+            print(e)
+            widget.set_tooltip_text("")
+
+#-----------------------------------------------------------------------------
+
+gobject.signal_new("row-activated", Timetable, gobject.SIGNAL_RUN_FIRST,
+                   None, (int,))
+
+gobject.signal_new("selection-changed", Timetable, gobject.SIGNAL_RUN_FIRST,
+                   None, (object,))
 
 #-----------------------------------------------------------------------------
@@ -520,5 +522,6 @@
                                         xscale = 1.0, yscale = 1.0)
 
-        filterFrame = gtk.Frame(xstr("timetable_filter"))
+        filterFrame = gtk.Frame()
+        filterFrame.set_label(xstr("timetable_filter"))
 
         filterVBox = gtk.VBox()
@@ -656,5 +659,5 @@
             typeFamilies.add(const.aircraftType2Family(aircraftType))
 
-        for (typeFamily, checkButton) in self._typeFamilyButtons.iteritems():
+        for (typeFamily, checkButton) in self._typeFamilyButtons.items():
             checkButton.set_sensitive(typeFamily in typeFamilies)
 
@@ -712,5 +715,5 @@
         """Update the timetable list."""
         aircraftTypes = []
-        for (aircraftFamily, button) in self._typeFamilyButtons.iteritems():
+        for (aircraftFamily, button) in self._typeFamilyButtons.items():
             if button.get_active():
                 aircraftTypes += const.aircraftFamily2Types[aircraftFamily]
@@ -752,5 +755,5 @@
         planes = [plane for plane in fleet
                   if plane.aircraftType == aircraftType]
-        planes.sort(cmp = lambda p1, p2: cmp(p1.tailNumber, p2.tailNumber))
+        planes.sort(key = lambda p: p.tailNumber)
 
         dialog = BookDialog(self, flightPair, planes)
Index: src/mlx/i18n.py
===================================================================
--- src/mlx/i18n.py	(revision 298)
+++ src/mlx/i18n.py	(revision 928)
@@ -24,5 +24,5 @@
 def setLanguage(programDirectory, language):
     """Setup the internationalization support for the given language."""
-    print "i18n.setLanguage", language
+    print("i18n.setLanguage", language)
     translation = _getTranslation(programDirectory, language)
     fallback = _getFallbackFor(programDirectory, language)
@@ -51,5 +51,5 @@
     If not found, the fallback language is searched. If that is not found
     either, the key itself is returned within curly braces."""
-    return _translation.ugettext(key)
+    return _translation.gettext(key)
     
 #------------------------------------------------------------------------------
Index: src/mlx/logger.py
===================================================================
--- src/mlx/logger.py	(revision 634)
+++ src/mlx/logger.py	(revision 921)
@@ -1,10 +1,11 @@
 
-from fs import sendMessage
-import const
-import util
+from .fs import sendMessage
+from . import const
+from . import util
 
 import sys
 import time
 import bisect
+from functools import total_ordering
 
 #--------------------------------------------------------------------------------------
@@ -34,4 +35,5 @@
     increasing IDs."""
 
+    @total_ordering
     class Entry(object):
         """An entry in the log."""
@@ -119,13 +121,19 @@
                                 id = self._id)
 
-        def __cmp__(self, other):
-            """Compare two entries
-
-            First their timestamps are compared, and if those are equal, then
-            their IDs."""
-            result = cmp(self._timestamp, other.timestamp)
-            if result==0:
-                result = cmp(self._id, other._id)
-            return result
+        def __eq__(self, other):
+            """Equality comparison"""
+            return self._timestamp == other.timestamp and \
+                self._id == other._id
+
+        def __ne__(self, other):
+            """Non-equality comparison"""
+            return self._timestamp != other.timestamp or \
+                self._id != other._id
+
+        def __lt__(self, other):
+            """Less-than comparison"""
+            return self._timestamp < other.timestamp or \
+                (self._timestamp == other.timestamp and
+                 self._id < other._id)
 
     class Fault(object):
@@ -235,5 +243,5 @@
     def debug(self, msg):
         """Log a debug message."""
-        print "[DEBUG]", msg
+        print("[DEBUG]", msg)
 
     def stage(self, timestamp, stage):
@@ -326,5 +334,5 @@
         """Get the rating of the flight so far."""
         totalScore = 100
-        for fault in self._faults.itervalues():
+        for fault in self._faults.values():
             score = fault.score
             if score==Logger.NO_GO_SCORE:
Index: src/mlx/mlx.py
===================================================================
--- src/mlx/mlx.py	(revision 800)
+++ src/mlx/mlx.py	(revision 919)
@@ -1,9 +1,9 @@
 
-from config import Config
-from i18n import setLanguage
-from sound import preInitializeSound, initializeSound, finalizeSound
-from util import secondaryInstallation
-from const import VERSION
-from watchdog import Watchdog
+from .config import Config
+from .i18n import setLanguage
+from .sound import preInitializeSound, initializeSound, finalizeSound
+from .util import secondaryInstallation
+from .const import VERSION
+from .watchdog import Watchdog
 
 import os
@@ -60,5 +60,5 @@
 def main():
     """The main operation of the program."""
-    from singleton import SingleInstance, raiseCallbackWrapper
+    from .singleton import SingleInstance, raiseCallbackWrapper
 
     global instance
@@ -86,6 +86,6 @@
     sys.stderr = StdIOHandler(gui)
 
-    print "MAVA Logger X " + VERSION + " debug log"
-    print "The initial configuration:"
+    print("MAVA Logger X " + VERSION + " debug log")
+    print("The initial configuration:")
     config.log()
 
Index: src/mlx/pirep.py
===================================================================
--- src/mlx/pirep.py	(revision 856)
+++ src/mlx/pirep.py	(revision 919)
@@ -1,8 +1,8 @@
 
-from util import utf2unicode
-from flight import Flight
-
-import const
-import cPickle as pickle
+from .util import utf2unicode
+from .flight import Flight
+
+from . import const
+import pickle as pickle
 import calendar
 import datetime
@@ -65,5 +65,5 @@
     def decodeFlightTypeText(s):
         """Decode the given flight type text."""
-        for (flighType, text) in PIREP._flightTypes.iteritems():
+        for (flighType, text) in PIREP._flightTypes.items():
             if s==text:
                 return flighType
@@ -124,7 +124,7 @@
                     pirep.mailWeight = pirep.bookedFlight.mailWeight
                 return pirep
-        except Exception, e:
-            print "Failed loading PIREP from %s: %s" % (path,
-                                                        utf2unicode(str(e)))
+        except Exception as e:
+            print("Failed loading PIREP from %s: %s" % (path,
+                                                        utf2unicode(str(e))))
             return None
 
@@ -367,7 +367,7 @@
                 pickle.dump(self, f)
             return None
-        except Exception, e:
+        except Exception as e:
             error = utf2unicode(str(e))
-            print u"Failed saving PIREP to %s: %s" % (path, error)
+            print("Failed saving PIREP to %s: %s" % (path, error))
             return error
 
Index: src/mlx/pyuipc_emu.py
===================================================================
--- src/mlx/pyuipc_emu.py	(revision 298)
+++ src/mlx/pyuipc_emu.py	(revision 919)
@@ -217,9 +217,9 @@
             results.append(int(vs / 60.0 * 0.3048 * 256))
         elif offset==0x0560:  # Latitude
-            results.append(long(latitude*10001750.0*65536.0*65536.0/90.0))
+            results.append(int(latitude*10001750.0*65536.0*65536.0/90.0))
         elif offset==0x0568:  # Longitude
-            results.append(long(longitude*65536.9*65536.0*65536.0*65536.0/360.0))
+            results.append(int(longitude*65536.9*65536.0*65536.0*65536.0/360.0))
         elif offset==0x0570:  # Aircraft altitude in metres (fractional part)
-            results.append(long( (altitude*0.3048*65536*65536)%(65536*65536)))
+            results.append(int( (altitude*0.3048*65536*65536)%(65536*65536)))
         elif offset==0x0574:  # Aircraft altitude in metres (whole part)
             results.append(int(altitude*.3048))
@@ -237,15 +237,15 @@
             centre_fuel = fuel_remaining - 2*side_tank_capacity
             if centre_fuel<0: centre_fuel = 0.0
-            results.append(long(round(centre_fuel/centre_tank_capacity*128.0*65536.0)))
+            results.append(int(round(centre_fuel/centre_tank_capacity*128.0*65536.0)))
         elif offset==0x0b78:  # Centre tank capacity (gallons)
-            results.append(long(round(centre_tank_capacity*KGTOLBS/fuel_weight)))
+            results.append(int(round(centre_tank_capacity*KGTOLBS/fuel_weight)))
         elif offset==0x0b7c or \
              offset==0x0b94:  # Left and right main tank level (%*128*65536)
             fuel = fuel_remaining/2
             if fuel>side_tank_capacity: fuel = side_tank_capacity
-            results.append(long(round(fuel/side_tank_capacity*128.0*65536.0)))
+            results.append(int(round(fuel/side_tank_capacity*128.0*65536.0)))
         elif offset==0x0b80 or \
              offset==0x0b98:  # Left and right main tank capacity (gallons)
-            results.append(long(round(side_tank_capacity*KGTOLBS/fuel_weight)))
+            results.append(int(round(side_tank_capacity*KGTOLBS/fuel_weight)))
         elif offset in [0x0b84, 0x0b88, 0x0b8c, 0x0b90,
                         0x0b9c, 0x0ba0, 0x0ba4, 0x0ba8,
@@ -253,5 +253,5 @@
                         0x1254, 0x1258, 0x125c, 0x1260]:
                               # Other tank capacities and levels
-            results.append(long(0))
+            results.append(int(0))
         elif offset==0x023a:  # Second of time
             results.append(int(tm[5]))
Index: src/mlx/pyuipc_sim.py
===================================================================
--- src/mlx/pyuipc_sim.py	(revision 877)
+++ src/mlx/pyuipc_sim.py	(revision 928)
@@ -1,4 +1,4 @@
 
-import const
+from . import const
 
 import cmd
@@ -9,5 +9,5 @@
 import sys
 import struct
-import cPickle
+import pickle
 import math
 
@@ -184,9 +184,9 @@
     def _readBCD(value):
         """Convert the given value into BCD format."""
-        bcd = (value/1000) % 10
+        bcd = (value//1000) % 10
         bcd <<= 4
-        bcd |= (value/100) % 10
+        bcd |= (value//100) % 10
         bcd <<= 4
-        bcd |= (value/10) % 10
+        bcd |= (value//10) % 10
         bcd <<= 4
         bcd |= value % 10
@@ -342,6 +342,6 @@
         try:
             return self._read(offset, type)
-        except Exception, e:
-            print "failed to read offset %04x: %s" % (offset, str(e))
+        except Exception as e:
+            print("failed to read offset %04x: %s" % (offset, str(e)))
             raise FSUIPCException(ERR_DATA)
 
@@ -360,5 +360,5 @@
             return int(index * flapsIncrement +
                        (self.flapsControl-self.flapsNotches[index]) *
-                       flapsIncrement /
+                       flapsIncrement //
                        (self.flapsNotches[index+1] - self.flapsNotches[index]))
 
@@ -414,9 +414,9 @@
             return 1 if self.overspeed else 0
         elif offset==0x0560:       # Latitude
-            return long(self.latitude * 10001750.0 * 65536.0 * 65536.0 / 90.0)
+            return int(self.latitude * 10001750.0 * 65536.0 * 65536.0 / 90.0)
         elif offset==0x0568:       # Longitude
-            return long(self.longitude * 65536.0 * 65536.0 * 65536.0 * 65536.0 / 360.0)
+            return int(self.longitude * 65536.0 * 65536.0 * 65536.0 * 65536.0 / 360.0)
         elif offset==0x0570:       # Altitude
-            return long(self.altitude * const.FEETTOMETRES * 65536.0 * 65536.0)
+            return int(self.altitude * const.FEETTOMETRES * 65536.0 * 65536.0)
         elif offset==0x0578:       # Pitch
             return int(self.pitch * 65536.0 * 65536.0 / 360.0)
@@ -542,5 +542,5 @@
         elif offset>=0x1400 and offset<=0x1f40 and \
              ((offset-0x1400)%48)==0: # Payload
-            return self.payload[ (offset - 0x1400) / 48 ]
+            return self.payload[ (offset - 0x1400) // 48 ]
         elif offset==0x2000:       # Engine #1 N1
             return self.n1[self.ENGINE_1]
@@ -568,5 +568,5 @@
         elif offset>=0x3210 and offset<0x3210+Values.HOTKEY_SIZE*4:
             tableOffset = offset - 0x3210
-            hotkeyIndex = tableOffset / 4
+            hotkeyIndex = tableOffset // 4
             index = tableOffset % 4
             if type=="b" or type=="c":
@@ -584,8 +584,8 @@
                     return value
                 else:
-                    print "Unhandled offset: %04x" % (offset,)
+                    print("Unhandled offset: %04x" % (offset,))
                     raise FSUIPCException(ERR_DATA)
             else:
-                print "Unhandled offset: %04x" % (offset,)
+                print("Unhandled offset: %04x" % (offset,))
                 raise FSUIPCException(ERR_DATA)
         elif offset==0x32fa:       # Message duration
@@ -602,11 +602,11 @@
             return self._getFlapsControl()
         elif offset==0x3bfa:       # Flaps increment
-            return 16383 / (len(self.flapsNotches)-1)
+            return 16383 // (len(self.flapsNotches)-1)
         elif offset==0x3bfc:       # ZFW
             return int(self.zfw * 256.0 * const.KGSTOLB)
         elif offset==0x3c00:       # Path of the current AIR file
-            return self.airPath
+            return bytes(self.airPath, "iso-8859-1")
         elif offset==0x3d00:       # Name of the current aircraft
-            return self.aircraftName
+            return bytes(self.aircraftName, "iso-8859-1")
         elif offset==0x6202:       # PMDG 737NG switches
             return self.pmdg_737ng_switches
@@ -616,5 +616,5 @@
             return 0 if self.xpdrC else 1
         else:
-            print "Unhandled offset: %04x" % (offset,)
+            print("Unhandled offset: %04x" % (offset,))
             raise FSUIPCException(ERR_DATA)
 
@@ -623,8 +623,8 @@
         try:
             return self._write(offset, value, type)
-        except TypeError, e:
+        except TypeError as e:
             raise e
-        except Exception, e:
-            print "failed to write offset %04x: %s" % (offset, str(e))
+        except Exception as e:
+            print("failed to write offset %04x: %s" % (offset, str(e)))
             raise FSUIPCException(ERR_DATA)
 
@@ -758,5 +758,5 @@
         elif offset==0x0bd0:       # Spoilers
             self.spoilters = 0 if value==0 \
-                             else (value - 4800) / (16383 - 4800)
+                             else (value - 4800) // (16383 - 4800)
         elif offset==0x0bdc:       # Flaps control
             numNotchesM1 = len(self.flapsNotches) - 1
@@ -768,5 +768,5 @@
                 self.flapsControl = self.flapsNotches[index]
                 self.flapsControl += (value - index * flapsIncrement) * \
-                    (self.flapsNotches[index+1] - self.flapsNotches[index]) / \
+                    (self.flapsNotches[index+1] - self.flapsNotches[index]) // \
                     flapsIncrement
         elif offset==0x0be0 or offset==0x0be4:    # Flaps left and  right
@@ -816,5 +816,5 @@
         elif offset>=0x1400 and offset<=0x1f40 and \
              ((offset-0x1400)%48)==0: # Payload
-            self.payload[ (offset - 0x1400) / 48 ] = value
+            self.payload[ (offset - 0x1400) // 48 ] = value
         elif offset==0x2000:       # Engine #1 N1
             self.n1[self.ENGINE_1] = value
@@ -840,5 +840,5 @@
         elif offset>=0x3210 and offset<0x3210+Values.HOTKEY_SIZE*4:
             tableOffset = offset - 0x3210
-            hotkeyIndex = tableOffset / 4
+            hotkeyIndex = tableOffset // 4
             index = tableOffset % 4
             if type=="b" or type=="c":
@@ -852,8 +852,8 @@
                     hotkey[3] = (value>>24) & 0xff
                 else:
-                    print "Unhandled offset: %04x for type '%s'" % (offset, type)
+                    print("Unhandled offset: %04x for type '%s'" % (offset, type))
                     raise FSUIPCException(ERR_DATA)
             else:
-                print "Unhandled offset: %04x for type '%s'" % (offset, type)
+                print("Unhandled offset: %04x for type '%s'" % (offset, type))
                 raise FSUIPCException(ERR_DATA)
         elif offset==0x32fa:       # Message duration
@@ -882,5 +882,5 @@
             self.xpdrC = value==0
         else:
-            print "Unhandled offset: %04x" % (offset,)
+            print("Unhandled offset: %04x" % (offset,))
             raise FSUIPCException(ERR_DATA)
 
@@ -1039,5 +1039,5 @@
                 (length,) = struct.unpack("I", clientSocket.recv(4))
                 data = clientSocket.recv(length)
-                (call, args) = cPickle.loads(data)
+                (call, args) = pickle.loads(data)
                 exception = None
 
@@ -1061,14 +1061,14 @@
                     else:
                         break
-                except Exception, e:
+                except Exception as e:
                     exception = e
 
                 if exception is None:
-                    data = cPickle.dumps((RESULT_RETURNED, result))
+                    data = pickle.dumps((RESULT_RETURNED, result))
                 else:
-                    data = cPickle.dumps((RESULT_EXCEPTION, str(exception)))
+                    data = pickle.dumps((RESULT_EXCEPTION, str(exception)))
                 clientSocket.send(struct.pack("I", len(data)) + data)
-        except Exception, e:
-            print >> sys.stderr, "pyuipc_sim.Server._process: failed with exception:", str(e)
+        except Exception as e:
+            print("pyuipc_sim.Server._process: failed with exception:", str(e), file=sys.stderr)
         finally:
             try:
@@ -1112,14 +1112,14 @@
     def quit(self):
         """Quit from the simulator."""
-        data = cPickle.dumps((CALL_QUIT, None))
+        data = pickle.dumps((CALL_QUIT, None))
         self._socket.send(struct.pack("I", len(data)) + data)
 
     def _call(self, command, data):
         """Perform a call with the given command and data."""
-        data = cPickle.dumps((command, [data]))
+        data = pickle.dumps((command, [data]))
         self._socket.send(struct.pack("I", len(data)) + data)
         (length,) = struct.unpack("I", self._socket.recv(4))
         data = self._socket.recv(length)
-        (resultCode, result) = cPickle.loads(data)
+        (resultCode, result) = pickle.loads(data)
         if resultCode==RESULT_RETURNED:
             return result
@@ -1234,5 +1234,5 @@
                                            lambda value: value * 90.0 /
                                            10001750.0 / 65536.0 / 65536.0,
-                                           lambda word: long(float(word) *
+                                           lambda word: int(float(word) *
                                                              10001750.0 *
                                                              65536.0 * 65536.0 / 90.0))
@@ -1240,5 +1240,5 @@
                                             lambda value: value * 360.0 /
                                             65536.0 / 65536.0 / 65536.0 / 65536.0,
-                                            lambda word: long(float(word) *
+                                            lambda word: int(float(word) *
                                                               65536.0 * 65536.0 *
                                                               65536.0 * 65536.0 /
@@ -1300,5 +1300,5 @@
                                            const.FEETTOMETRES / 65536.0 /
                                            65536.0,
-                                           lambda word: long(float(word) *
+                                           lambda word: int(float(word) *
                                                              const.FEETTOMETRES *
                                                              65536.0 * 65536.0))
@@ -1487,5 +1487,5 @@
             self._valueHandlers["hotkey%d" % (i,)] = ([(0x3210 + i*4, "u")],
                                                       lambda value: "0x%08x" % (value,),
-                                                      lambda word: long(word, 16))
+                                                      lambda word: int(word, 16))
 
         self._valueHandlers["cog"] = ([(0x2ef8, "f")], lambda value: value,
@@ -1537,5 +1537,5 @@
         """Handle unhandle commands."""
         if line=="EOF":
-            print
+            print()
             return self.do_quit("")
         else:
@@ -1548,5 +1548,5 @@
         for name in names:
             if name not in self._valueHandlers:
-                print >> sys.stderr, "Unknown variable: " + name
+                print("Unknown variable: " + name, file=sys.stderr)
                 return False
             valueHandler = self._valueHandlers[name]
@@ -1565,10 +1565,10 @@
                                         else thisResults)
 
-                print name + "=" + str(value)
+                print(name + "=" + str(value))
 
                 index += numResults
                 i+=1
-        except Exception, e:
-            print >> sys.stderr, "Failed to read data: " + str(e)
+        except Exception as e:
+            print("Failed to read data: " + str(e), file=sys.stderr)
 
         return False
@@ -1576,5 +1576,5 @@
     def help_get(self):
         """Print help for the get command."""
-        print "get <variable> [<variable>...]"
+        print("get <variable> [<variable>...]")
 
     def complete_get(self, text, line, begidx, endidx):
@@ -1608,10 +1608,10 @@
             words = argument.split("=")
             if len(words)!=2:
-                print >> sys.stderr, "Invalid argument: " + argument
+                print("Invalid argument: " + argument, file=sys.stderr)
                 return False
 
             (name, value) = words
             if name not in self._valueHandlers:
-                print >> sys.stderr, "Unknown variable: " + name
+                print("Unknown variable: " + name, file=sys.stderr)
                 return False
 
@@ -1625,14 +1625,14 @@
                     data.append((offset, type, values[index]))
                     index += 1
-            except Exception, e:
-                print >> sys.stderr, "Invalid value '%s' for variable %s: %s" % \
-                      (value, name, str(e))
+            except Exception as e:
+                print("Invalid value '%s' for variable %s: %s" % \
+                      (value, name, str(e)), file=sys.stderr)
                 return False
 
         try:
             self._client.write(data)
-            print "Data written"
-        except Exception, e:
-            print >> sys.stderr, "Failed to write data: " + str(e)
+            print("Data written")
+        except Exception as e:
+            print("Failed to write data: " + str(e), file=sys.stderr)
 
         return False
@@ -1640,5 +1640,5 @@
     def help_set(self):
         """Print help for the set command."""
-        print "set <variable>=<value> [<variable>=<value>...]"
+        print("set <variable>=<value> [<variable>=<value>...]")
 
     def complete_set(self, text, line, begidx, endidx):
@@ -1654,12 +1654,12 @@
             value = int(args)
             self._client.setVersion(value)
-            print "Emulating version %d" % (value,)
-        except Exception, e:
-            print >> sys.stderr, "Failed to set the version: " + str(e)
+            print("Emulating version %d" % (value,))
+        except Exception as e:
+            print("Failed to set the version: " + str(e), file=sys.stderr)
 
     def help_setversion(self, usage = False):
         """Help for the setversion command"""
-        if usage: print "Usage:",
-        print "setversion <number>"
+        if usage: print("Usage:", end=' ')
+        print("setversion <number>")
 
     def do_close(self, args):
@@ -1667,7 +1667,7 @@
         try:
             self._client.close()
-            print "Connection closed"
-        except Exception, e:
-            print >> sys.stderr, "Failed to close the connection: " + str(e)
+            print("Connection closed")
+        except Exception as e:
+            print("Failed to close the connection: " + str(e), file=sys.stderr)
 
     def do_failopen(self, args):
@@ -1676,12 +1676,12 @@
             value = self.str2bool(args)
             self._client.failOpen(value)
-            print "Opening will%s fail" % ("" if value else " not",)
-        except Exception, e:
-            print >> sys.stderr, "Failed to set open failure: " + str(e)
+            print("Opening will%s fail" % ("" if value else " not",))
+        except Exception as e:
+            print("Failed to set open failure: " + str(e), file=sys.stderr)
 
     def help_failopen(self, usage = False):
         """Help for the failopen command"""
-        if usage: print "Usage:",
-        print "failopen yes|no"
+        if usage: print("Usage:", end=' ')
+        print("failopen yes|no")
 
     def complete_failopen(self, text, line, begidx, endidx):
Index: src/mlx/rpc.py
===================================================================
--- src/mlx/rpc.py	(revision 889)
+++ src/mlx/rpc.py	(revision 928)
@@ -1,6 +1,6 @@
-import const
-import rpccommon
-
-from common import MAVA_BASE_URL
+from . import const
+from . import rpccommon
+
+from .common import MAVA_BASE_URL
 
 import jsonrpclib
@@ -28,5 +28,5 @@
         For all other names, the value will be stored as the same-named
         attribute."""
-        for (key, value) in value.iteritems():
+        for (key, value) in value.items():
             if key in instructions:
                 instruction = instructions[key]
@@ -37,6 +37,6 @@
                     value = instruction(value)
                 except:
-                    print >> sys.stderr, "Failed to convert value '%s' of attribute '%s':" % \
-                        (value, key)
+                    print("Failed to convert value '%s' of attribute '%s':" % \
+                        (value, key), file=sys.stderr)
                     import traceback
                     traceback.print_exc()
@@ -111,9 +111,12 @@
                 cs1 = int(self.callsign[2:])
                 cs2 = int(other.callsign[2:])
-                return cmp(cs1, cs2)
+                return 0 if cs1==cs2 else -1 if cs1<cs2 else 1
             except:
-                return cmp(self.callsign, other.callsign)
+                return 0 if self.callsign==other.callsign \
+                    else -1 if self.callsign<other.callsign else 1
         else:
-            return cmp(getattr(self, name), getattr(other, name))
+            v1 = getattr(self, name)
+            v2 = getattr(other, name)
+            return 0 if v1==v2 else -1 if v1<v2 else 1
 
     def __repr__(self):
@@ -166,6 +169,5 @@
                 flightPairs.append(ScheduledFlightPair(flight))
 
-        flightPairs.sort(cmp = lambda pair1, pair2:
-                         cmp(pair1.flight0.date, pair2.flight0.date))
+        flightPairs.sort(key = lambda pair: pair.flight0.date)
 
         return flightPairs
@@ -297,26 +299,26 @@
     def writeIntoFile(self, f):
         """Write the flight into a file."""
-        print >> f, "callsign=%s" % (self.callsign,)
+        print("callsign=%s" % (self.callsign,), file=f)
         date = self.departureTime.date()
-        print >> f, "date=%04d-%02d-%0d" % (date.year, date.month, date.day)
-        print >> f, "dep_airport=%s" % (self.departureICAO,)
-        print >> f, "dest_airport=%s" % (self.arrivalICAO,)
-        print >> f, "planecode=%s" % \
-              (BookedFlight.TYPE2TYPECODE[self.aircraftType],)
-        print >> f, "planetype=%s" % (self.aircraftTypeName,)
-        print >> f, "tail_nr=%s" % (self.tailNumber,)
-        print >> f, "passenger=%d" % (self.numPassengers,)
-        print >> f, "crew=%d" % (self.numCrew,)
-        print >> f, "bag=%d" % (self.bagWeight,)
-        print >> f, "cargo=%d" % (self.cargoWeight,)
-        print >> f, "mail=%d" % (self.mailWeight,)
-        print >> f, "flight_route=%s" % (self.route,)
+        print("date=%04d-%02d-%0d" % (date.year, date.month, date.day), file=f)
+        print("dep_airport=%s" % (self.departureICAO,), file=f)
+        print("dest_airport=%s" % (self.arrivalICAO,), file=f)
+        print("planecode=%s" % \
+              (BookedFlight.TYPE2TYPECODE[self.aircraftType],), file=f)
+        print("planetype=%s" % (self.aircraftTypeName,), file=f)
+        print("tail_nr=%s" % (self.tailNumber,), file=f)
+        print("passenger=%d" % (self.numPassengers,), file=f)
+        print("crew=%d" % (self.numCrew,), file=f)
+        print("bag=%d" % (self.bagWeight,), file=f)
+        print("cargo=%d" % (self.cargoWeight,), file=f)
+        print("mail=%d" % (self.mailWeight,), file=f)
+        print("flight_route=%s" % (self.route,), file=f)
         departureTime = self.departureTime
-        print >> f, "departure_time=%02d\\:%02d\\:%02d" % \
-              (departureTime.hour, departureTime.minute, departureTime.second)
+        print("departure_time=%02d\\:%02d\\:%02d" % \
+              (departureTime.hour, departureTime.minute, departureTime.second), file=f)
         arrivalTime = self.arrivalTime
-        print >> f, "arrival_time=%02d\\:%02d\\:%02d" % \
-              (arrivalTime.hour, arrivalTime.minute, arrivalTime.second)
-        print >> f, "foglalas_id=%s" % ("0" if self.id is None else self.id,)
+        print("arrival_time=%02d\\:%02d\\:%02d" % \
+              (arrivalTime.hour, arrivalTime.minute, arrivalTime.second), file=f)
+        print("foglalas_id=%s" % ("0" if self.id is None else self.id,), file=f)
 
 #---------------------------------------------------------------------------------------
@@ -468,5 +470,5 @@
 
         md5 = hashlib.md5()
-        md5.update(password)
+        md5.update(password.encode("utf-8"))
         self._passwordHash = md5.hexdigest()
 
@@ -523,6 +525,5 @@
 
         for flights in [bookedFlights, reportedFlights, rejectedFlights]:
-            flights.sort(cmp = lambda flight1, flight2:
-                         cmp(flight1.departureTime, flight2.departureTime))
+            flights.sort(key = lambda flight: flight.departureTime)
 
         return (bookedFlights, reportedFlights, rejectedFlights)
Index: src/mlx/rpccommon.py
===================================================================
--- src/mlx/rpccommon.py	(revision 742)
+++ src/mlx/rpccommon.py	(revision 919)
@@ -3,5 +3,5 @@
 #------------------------------------------------------------------------------
 
-import const
+from . import const
 
 #------------------------------------------------------------------------------
@@ -51,5 +51,5 @@
         """Check if the gate of the given plane conflicts with another plane's
         position."""
-        for p in self._planes.itervalues():
+        for p in self._planes.values():
             if p.tailNumber!=plane.tailNumber and \
                p.status==const.PLANE_HOME and \
@@ -62,5 +62,5 @@
         """Get a set containing the numbers of the gates occupied by planes."""
         gateNumbers = set()
-        for p in self._planes.itervalues():
+        for p in self._planes.values():
             if p.status==const.PLANE_HOME and p.gateNumber:
                 gateNumbers.add(p.gateNumber)
@@ -80,5 +80,5 @@
     def __iter__(self):
         """Get an iterator over the planes."""
-        for plane in self._planes.itervalues():
+        for plane in self._planes.values():
             yield plane
 
Index: src/mlx/singleton.py
===================================================================
--- src/mlx/singleton.py	(revision 401)
+++ src/mlx/singleton.py	(revision 919)
@@ -1,4 +1,4 @@
 
-from util import utf2unicode
+from .util import utf2unicode
 
 import os
@@ -59,8 +59,8 @@
                         break
 
-                    print "singleton._PipeServer.run: created the pipe"
+                    print("singleton._PipeServer.run: created the pipe")
                     try:
                         if win32pipe.ConnectNamedPipe(handle)==0:
-                            print "singleton._PipeServer.run: client connection received"
+                            print("singleton._PipeServer.run: client connection received")
                             (code, message) = \
                                 win32file.ReadFile(handle,
@@ -69,17 +69,17 @@
 
                             if code==0:
-                                print "singleton._PipeServer.run: message received from client"
+                                print("singleton._PipeServer.run: message received from client")
                                 self._raiseCallback()
                             else:
-                                print "singleton._PipeServer.run: failed to read from the pipe"
-                    except Exception, e:
-                        print "singleton._PipeServer.run: exception:",
-                        print utf2unicode(str(e))
+                                print("singleton._PipeServer.run: failed to read from the pipe")
+                    except Exception as e:
+                        print("singleton._PipeServer.run: exception:", end=' ')
+                        print(utf2unicode(str(e)))
                     finally:
                         win32pipe.DisconnectNamedPipe(handle)
                         win32file.CloseHandle(handle)
-            except Exception, e:
-                print "singleton._PipeServer.run: fatal exception:",
-                print utf2unicode(str(e))
+            except Exception as e:
+                print("singleton._PipeServer.run: fatal exception:", end=' ')
+                print(utf2unicode(str(e)))
                             
         def _createPipe(self):
@@ -96,5 +96,5 @@
                                                None)
             if handle==win32file.INVALID_HANDLE_VALUE:
-                print "singleton._PipeServer.run: could not create the handle"
+                print("singleton._PipeServer.run: could not create the handle")
                 return None
             else:
@@ -144,10 +144,10 @@
                     f.close()
                     return
-                except Exception, e:
-                    print "SingleInstance._notifySingleton: failed:",
-                    print utf2unicode(str(e))
+                except Exception as e:
+                    print("SingleInstance._notifySingleton: failed:", end=' ')
+                    print(utf2unicode(str(e)))
                     time.sleep(0.5)
         
-        def __nonzero__(self):
+        def __bool__(self):
             """Return a boolean representation of the object.
 
@@ -194,7 +194,7 @@
                     s.recv(64)
                     self._raiseCallback()
-            except Exception, e:
-                print "singleton._SocketServer.run: fatal exception:",
-                print utf2unicode(str(e))
+            except Exception as e:
+                print("singleton._SocketServer.run: fatal exception:", end=' ')
+                print(utf2unicode(str(e)))
     
     class SingleInstance(object):
@@ -218,5 +218,5 @@
                 fcntl.lockf(self._lockFile, fcntl.LOCK_EX | fcntl.LOCK_NB)
                 self._isSingle = True
-            except Exception, e:
+            except Exception as e:
                 self._lockFile.close()
                 self._lockFile = None
@@ -259,10 +259,10 @@
                     s.close()
                     return
-                except Exception, e:
-                    print "singleton.SingleInstance._notifySingleton: failed:",
-                    print utf2unicode(str(e))
+                except Exception as e:
+                    print("singleton.SingleInstance._notifySingleton: failed:", end=' ')
+                    print(utf2unicode(str(e)))
                     time.sleep(0.5)
 
-        def __nonzero__(self):
+        def __bool__(self):
             """Return a boolean representation of the object.
 
@@ -299,11 +299,11 @@
 if __name__=="__main__":
     def raiseCallback():
-        print "Raise the window!"
+        print("Raise the window!")
 
     instance = SingleInstance("mlx", raiseCallback)
     if instance:
-        print "The first instance"
+        print("The first instance")
         time.sleep(10)
     else:
-        print "The program is already running."
-
+        print("The program is already running.")
+
Index: src/mlx/sound.py
===================================================================
--- src/mlx/sound.py	(revision 800)
+++ src/mlx/sound.py	(revision 919)
@@ -1,4 +1,4 @@
 
-from util import utf2unicode
+from .util import utf2unicode
 
 import os
@@ -113,10 +113,10 @@
                     success = True
                     try:
-                        print "Closing", alias
+                        print("Closing", alias)
                         self._mci.send("close " + alias)
-                        print "Closed", alias
-                    except Exception, e:
-                        print "Failed closing " + alias + ":",
-                        print utf2unicode(str(e))
+                        print("Closed", alias)
+                    except Exception as e:
+                        print("Failed closing " + alias + ":", end=' ')
+                        print(utf2unicode(str(e)))
                         success = False
 
@@ -130,5 +130,5 @@
                     try:
                         alias = "mlxsound%d" % (counter,)
-                        print "Starting to play", path, "as", alias
+                        print("Starting to play", path, "as", alias)
                         self._mci.send("open \"%s\" alias %s" % \
                                        (path, alias))
@@ -144,8 +144,8 @@
                             self._pending.append((timeout, (alias, finishData)))
                             self._pending.sort()
-                        print "Started to play", path
-                    except Exception, e:
-                        print "Failed to start playing " + path + ":",
-                        print utf2unicode(str(e))
+                        print("Started to play", path)
+                    except Exception as e:
+                        print("Failed to start playing " + path + ":", end=' ')
+                        print(utf2unicode(str(e)))
                         (finishCallback, extra) = finishData
                         if finishCallback is not None:
@@ -220,5 +220,5 @@
 
             Gst.init(None)
-        except Exception, e:
+        except Exception as e:
             outQueue.put(False)
             outQueue.put(e)
@@ -351,6 +351,6 @@
         else:
             exception = _inQueue.get()
-            print "The Gst library is missing from your system. It is needed for sound playback on Linux:"
-            print exception
+            print("The Gst library is missing from your system. It is needed for sound playback on Linux:")
+            print(exception)
 
     def startSound(name, finishCallback = None, extra = None):
@@ -387,5 +387,5 @@
 
     def callback(result, extra):
-        print "callback", result, extra
+        print("callback", result, extra)
 
     preInitializeSound()
@@ -393,5 +393,5 @@
     soundsPath = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                               "..", "..", "sounds"))
-    print "soundsPath:", soundsPath
+    print("soundsPath:", soundsPath)
     initializeSound(soundsPath)
     startSound("notam.mp3", finishCallback = callback, extra= "notam.mp3")
Index: src/mlx/soundsched.py
===================================================================
--- src/mlx/soundsched.py	(revision 352)
+++ src/mlx/soundsched.py	(revision 919)
@@ -1,6 +1,6 @@
 
-from sound import startSound
-import const
-import fs
+from .sound import startSound
+from . import const
+from . import fs
 
 import threading
@@ -64,7 +64,7 @@
         """Called when the playback of thee sound has finished (or failed)."""
         if success is None:
-            print "Failed to start sound", self._name
+            print("Failed to start sound", self._name)
         elif not success:
-            print "Failed to finish sound", self._name
+            print("Failed to finish sound", self._name)
         with Sound._lock:            
             self._playing -= 1
Index: src/mlx/test.py
===================================================================
--- src/mlx/test.py	(revision 27)
+++ src/mlx/test.py	(revision 919)
@@ -1,9 +1,9 @@
 # Test module
 
-import fs
-import flight
-import logger
-import acft
-import const
+from . import fs
+from . import flight
+from . import logger
+from . import acft
+from . import const
 
 import time
@@ -11,5 +11,5 @@
 
 def callback(data, extra):
-    print data
+    print(data)
 
 def main():
Index: src/mlx/update.py
===================================================================
--- src/mlx/update.py	(revision 953)
+++ src/mlx/update.py	(revision 950)
@@ -1,9 +1,9 @@
 
-from config import Config
-from util import utf2unicode
+from .config import Config
+from .util import utf2unicode
 
 import os
 import sys
-import urllib2
+import urllib.request, urllib.error, urllib.parse
 import tempfile
 import socket
@@ -11,4 +11,5 @@
 import hashlib
 import traceback
+import io
 
 if os.name=="nt":
@@ -57,5 +58,5 @@
 
         Each file is returned as a 3-tuple with items as in the file."""
-        for (path, (size, sum)) in self._files.iteritems():
+        for (path, (size, sum)) in self._files.items():
             yield (path, size, sum)
 
@@ -99,5 +100,5 @@
     def writeInto(self, file):
         """Write the manifest into the file at the given path."""
-        for (path, (size, sum)) in self._files.iteritems():
+        for (path, (size, sum)) in self._files.items():
             file.write("%s\t%d\t%s\n" % (path, size, sum))
 
@@ -201,5 +202,5 @@
     def _send(self, words):
         """Send the given words via the socket."""
-        self._sock.send("\t".join(words) + "\n")
+        self._sock.send(bytes("\t".join(words) + "\n", "utf-8"))
 
 #------------------------------------------------------------------------------
@@ -213,6 +214,6 @@
         with open(manifestPath, "rt") as f:
             manifest.readFrom(f)
-    except Exception, e:
-        print "Error reading the manifest, ignoring:", utf2unicode(str(e))
+    except Exception as e:
+        print("Error reading the manifest, ignoring:", utf2unicode(str(e)))
         manifest = Manifest()
 
@@ -232,10 +233,12 @@
     try:
         updateManifest = Manifest()
-        f= urllib2.urlopen(updateURL + "/" + manifestName)
-        updateManifest.readFrom(f)
-
-    except Exception, e:
+        reply = urllib.request.urlopen(updateURL + "/" + manifestName)
+        charset = reply.headers.get_content_charset()
+        content = reply.read().decode("utf-8" if charset is None else charset)
+        updateManifest.readFrom(io.StringIO(content))
+
+    except Exception as e:
         error = utf2unicode(str(e))
-        print >> sys.stderr, "Error downloading manifest:", error
+        print("Error downloading manifest:", error, file=sys.stderr)
         listener.failed(error)
         return None
@@ -296,5 +299,5 @@
         try:
             sum = hashlib.md5()
-            sum.update(path)
+            sum.update(bytes(path, "utf-8"))
             toremoveDir = getToremoveDir(toremoveDir, directory)
             targetPath = os.path.join(toremoveDir, sum.hexdigest())
@@ -304,6 +307,6 @@
                 pass
             os.rename(path, targetPath)
-        except Exception, e:
-            print "Cannot remove file " + path + ": " + utf2unicode(str(e))
+        except Exception as e:
+            print("Cannot remove file " + path + ": " + utf2unicode(str(e)))
 
 #------------------------------------------------------------------------------
@@ -365,5 +368,5 @@
                 
             with open(targetFile, "wb") as fout:
-                fin = urllib2.urlopen(updateURL + "/" + path)
+                fin = urllib.request.urlopen(updateURL + "/" + path)
                 while True:
                     data = fin.read(4096)
@@ -397,10 +400,10 @@
         
         listener.done()
-    except Exception, e:
+    except Exception as e:
         exc = traceback.format_exc()
-        print >> sys.stderr, utf2unicode(exc)
+        print(utf2unicode(exc), file=sys.stderr)
         
         error = utf2unicode(str(e))
-        print >> sys.stderr, "Error:", error
+        print("Error:", error, file=sys.stderr)
 
         listener.failed(error)
@@ -415,5 +418,5 @@
         f.close()
         return True
-    except Exception, e:
+    except Exception as e:
         return False
     finally:
@@ -445,8 +448,8 @@
                 listener.downloadedManifest()
             elif command=="setTotalSize":
-                listener.setTotalSize(int(words[1]), long(words[2]),
+                listener.setTotalSize(int(words[1]), int(words[2]),
                                       int(words[3]), int(words[4]))
             elif command=="setDownloaded":
-                listener.setDownloaded(long(words[1]))
+                listener.setDownloaded(int(words[1]))
             elif command=="startRenaming":
                 listener.startRenaming()
@@ -463,7 +466,7 @@
             elif command=="failed":
                 listener.failed(words[1])
-        except Exception, e:
-            print >> sys.stderr, "Failed to parse line '%s': %s" % \
-                  (line, utf2unicode(str(e)))
+        except Exception as e:
+            print("Failed to parse line '%s': %s" % \
+                  (line, utf2unicode(str(e))), file=sys.stderr)
 
     return buffer
@@ -511,5 +514,5 @@
                 break;
 
-            buffer += data
+            buffer += str(data, "utf-8")
             buffer = processMLXUpdate(buffer, listener)
 
@@ -520,7 +523,7 @@
             process.wait()
         
-    except Exception, e:
+    except Exception as e:
         error = utf2unicode(str(e))
-        print >> sys.stderr, "Failed updating:", error
+        print("Failed updating:", error, file=sys.stderr)
         listener.failed(error)
     finally:
@@ -569,10 +572,10 @@
             updateFiles(directory, updateURL, listener, updateManifest,
                         modifiedAndNew, removed, localRemoved)
-    except Exception, e:
+    except Exception as e:
         exc = traceback.format_exc()
-        print >> sys.stderr, utf2unicode(exc)
+        print(utf2unicode(exc), file=sys.stderr)
         
         error = utf2unicode(str(e))
-        print >> sys.stderr, "Update error:", error
+        print("Update error:", error, file=sys.stderr)
         
         listener.failed(error)
@@ -602,5 +605,5 @@
     except:
         exc = traceback.format_exc()
-        print >> sys.stderr, utf2unicode(exc)
+        print(utf2unicode(exc), file=sys.stderr)
 
 #------------------------------------------------------------------------------
Index: src/mlx/util.py
===================================================================
--- src/mlx/util.py	(revision 784)
+++ src/mlx/util.py	(revision 929)
@@ -43,7 +43,7 @@
 #------------------------------------------------------------------------------
 
-def getCoordinateString((latitude, longitude)):
+def getCoordinateString(xxx_todo_changeme):
     """Get the string representation of the given coordinate pair."""
-
+    (latitude, longitude) = xxx_todo_changeme
     latitude_str = getLatitudeString(latitude)
     longitude_str = getLongitudeString(longitude)
@@ -79,5 +79,5 @@
     (deg, min, sec, _sign) = getDegMinSec(degree)
 
-    return u"%s%d\u00b0%02d\u2032%02d\u2033" % (prefix, deg, min, sec)
+    return "%s%d\u00b0%02d\u2032%02d\u2033" % (prefix, deg, min, sec)
 
 #------------------------------------------------------------------------------
@@ -174,9 +174,18 @@
 def utf2unicode(text):
     """Convert the given text from UTF-8 encoding to unicode."""
+    if isinstance(text, str):
+        if text.startswith("list indices must be"):
+            import traceback
+            traceback.print_exc()
+
+        return text
+
     try:
-        return unicode(_utf8decoder(text)[0])
+        return str(_utf8decoder(text)[0])
     except:
+        import traceback
+        traceback.print_exc()
         try:
-            return unicode(_latin2decoder(text)[0])
+            return str(_latin2decoder(text)[0])
         except:
-            return unicode(list(text))
+            return str(list(text))
Index: src/mlx/watchdog.py
===================================================================
--- src/mlx/watchdog.py	(revision 535)
+++ src/mlx/watchdog.py	(revision 919)
@@ -60,7 +60,7 @@
 
         if logTimeout:
-            print "Watchdog client %s has timed out!" % (self._name)
+            print("Watchdog client %s has timed out!" % (self._name))
         elif logCleared:
-            print "Watchdog client %s has been cleared." % (self._name)
+            print("Watchdog client %s has been cleared." % (self._name))
 
 #-----------------------------------------------------------------------------
@@ -115,5 +115,5 @@
 
             if t>=nextLogTime:
-                print "Watchdog.run: running"
+                print("Watchdog.run: running")
                 while t>=nextLogTime:
                     nextLogTime += self.LOG_INTERVAL
Index: src/mlx/web.py
===================================================================
--- src/mlx/web.py	(revision 859)
+++ src/mlx/web.py	(revision 930)
@@ -1,24 +1,25 @@
 
-import const
-import util
-from rpc import Registration
-import rpc
-import rpccommon
-
-from common import MAVA_BASE_URL
-from pirep import PIREP
+from . import const
+from . import util
+from .rpc import Registration
+from . import rpc
+from . import rpccommon
+
+from .common import MAVA_BASE_URL
+from .pirep import PIREP
 
 import threading
 import sys
-import urllib
-import urllib2
+import urllib.request, urllib.parse, urllib.error
+import urllib.request, urllib.error, urllib.parse
 import hashlib
 import time
+import re
 import datetime
 import codecs
 import traceback
 import xml.sax
-import xmlrpclib
-import HTMLParser
+import xmlrpc.client
+import html.parser
 
 #---------------------------------------------------------------------------------------
@@ -160,5 +161,5 @@
 
         date = readline(f)
-        print "web.BookedFlight.readFromWeb: date:", date
+        print("web.BookedFlight.readFromWeb: date:", date)
         if date=="0000-00-00": date = "0001-01-01"
 
@@ -233,6 +234,6 @@
 
                 if not lineOK:
-                    print "web.BookedFlight.readFromFile: line %d is invalid" % \
-                          (lineNumber,)
+                    print("web.BookedFlight.readFromFile: line %d is invalid" % \
+                          (lineNumber,))
 
             line = f.readline()
@@ -290,26 +291,26 @@
     def writeIntoFile(self, f):
         """Write the flight into a file."""
-        print >> f, "callsign=%s" % (self.callsign,)
+        print("callsign=%s" % (self.callsign,), file=f)
         date = self.departureTime.date()
-        print >> f, "date=%04d-%02d-%0d" % (date.year, date.month, date.day)
-        print >> f, "dep_airport=%s" % (self.departureICAO,)
-        print >> f, "dest_airport=%s" % (self.arrivalICAO,)
-        print >> f, "planecode=%s" % \
-              (BookedFlight.TYPE2TYPECODE[self.aircraftType],)
-        print >> f, "planetype=%s" % (self.aircraftTypeName,)
-        print >> f, "tail_nr=%s" % (self.tailNumber,)
-        print >> f, "passenger=%d" % (self.numPassengers,)
-        print >> f, "crew=%d" % (self.numCrew,)
-        print >> f, "bag=%d" % (self.bagWeight,)
-        print >> f, "cargo=%d" % (self.cargoWeight,)
-        print >> f, "mail=%d" % (self.mailWeight,)
-        print >> f, "flight_route=%s" % (self.route,)
+        print("date=%04d-%02d-%0d" % (date.year, date.month, date.day), file=f)
+        print("dep_airport=%s" % (self.departureICAO,), file=f)
+        print("dest_airport=%s" % (self.arrivalICAO,), file=f)
+        print("planecode=%s" % \
+              (BookedFlight.TYPE2TYPECODE[self.aircraftType],), file=f)
+        print("planetype=%s" % (self.aircraftTypeName,), file=f)
+        print("tail_nr=%s" % (self.tailNumber,), file=f)
+        print("passenger=%d" % (self.numPassengers,), file=f)
+        print("crew=%d" % (self.numCrew,), file=f)
+        print("bag=%d" % (self.bagWeight,), file=f)
+        print("cargo=%d" % (self.cargoWeight,), file=f)
+        print("mail=%d" % (self.mailWeight,), file=f)
+        print("flight_route=%s" % (self.route,), file=f)
         departureTime = self.departureTime
-        print >> f, "departure_time=%02d\\:%02d\\:%02d" % \
-              (departureTime.hour, departureTime.minute, departureTime.second)
+        print("departure_time=%02d\\:%02d\\:%02d" % \
+              (departureTime.hour, departureTime.minute, departureTime.second), file=f)
         arrivalTime = self.arrivalTime
-        print >> f, "arrival_time=%02d\\:%02d\\:%02d" % \
-              (arrivalTime.hour, arrivalTime.minute, arrivalTime.second)
-        print >> f, "foglalas_id=%s" % ("0" if self.id is None else self.id,)
+        print("arrival_time=%02d\\:%02d\\:%02d" % \
+              (arrivalTime.hour, arrivalTime.minute, arrivalTime.second), file=f)
+        print("foglalas_id=%s" % ("0" if self.id is None else self.id,), file=f)
 
     def _readAircraftType(self, f):
@@ -364,5 +365,5 @@
 
         except:
-            print >> sys.stderr, "Plane string is invalid: '" + s + "'"
+            print("Plane string is invalid: '" + s + "'", file=sys.stderr)
             self.tailNumber = None
 
@@ -470,9 +471,9 @@
 #------------------------------------------------------------------------------
 
-class PilotsWebNOTAMsParser(HTMLParser.HTMLParser):
+class PilotsWebNOTAMsParser(html.parser.HTMLParser):
     """XML handler for the NOTAM query results on the PilotsWeb website."""
     def __init__(self):
         """Construct the handler."""
-        HTMLParser.HTMLParser.__init__(self)
+        html.parser.HTMLParser.__init__(self)
 
         self._notams = []
@@ -513,9 +514,9 @@
         try:
             notam = self._parseCurrentNOTAM2()
-        except Exception, e:
-            print "Error parsing current NOTAM: " + str(e)
+        except Exception as e:
+            print("Error parsing current NOTAM: " + str(e))
 
         if notam is None:
-            print "Could not parse NOTAM: " + self._currentNOTAM
+            print("Could not parse NOTAM: " + self._currentNOTAM)
             if self._currentNOTAM:
                 self._notams.append(self._currentNOTAM + "\n")
@@ -526,5 +527,5 @@
         """Parse the current NOTAM, if possible, and return a NOTAM object."""
         lines = self._currentNOTAM.splitlines()
-        lines = map(lambda line: line.strip(), lines)
+        lines = [line.strip() for line in lines]
 
         if len(lines)<4:
@@ -578,6 +579,9 @@
     def _parseCurrentNOTAM2(self):
         """Parse the current NOTAM with a second, more flexible method."""
+        self._currentNOTAM = self._currentNOTAM.replace("\\n", "\n")
         lines = self._currentNOTAM.splitlines()
-        lines = map(lambda line: line.strip(), lines)
+        if len(lines)==1:
+            lines = lines[0].splitlines()
+        lines = [line.strip() for line in lines]
 
         if not lines:
@@ -592,5 +596,5 @@
                 lines = lines[:-1]
 
-        lines = map(lambda line: line.strip(), lines)
+        lines = [line.strip() for line in lines]
         contents = " ".join(lines).split()
 
@@ -614,4 +618,5 @@
 
         def parseTime(item):
+            item = re.sub("([0-9]+).*", "\\1", item)
             try:
                 return datetime.datetime.strptime(item, "%y%m%d%H%M")
@@ -653,6 +658,6 @@
         """Get a representation of the result."""
         s = "<Result:"
-        for (key, value) in self.__dict__.iteritems():
-            s += " " + key + "=" + unicode(value)
+        for (key, value) in self.__dict__.items():
+            s += " " + key + "=" + str(value)
         s += ">"
         return s
@@ -688,5 +693,5 @@
             result = self.run()
             returned = True
-        except Exception, e:
+        except Exception as e:
             traceback.print_exc()
             result = e
@@ -695,6 +700,6 @@
         try:
             self._callback(returned, result)
-        except Exception, e:
-            print >> sys.stderr, "web.Handler.Request.perform: callback throwed an exception: " + util.utf2unicode(str(e))
+        except Exception as e:
+            print("web.Handler.Request.perform: callback throwed an exception: " + util.utf2unicode(str(e)), file=sys.stderr)
             #traceback.print_exc()
 
@@ -769,5 +774,5 @@
         result = Result()
 
-        f = urllib2.urlopen(url, timeout = 10.0)
+        f = urllib.request.urlopen(url, timeout = 10.0)
 
         status = readline(f)
@@ -791,7 +796,5 @@
                 result.flights.append(flight)
 
-            result.flights.sort(cmp = lambda flight1, flight2:
-                                cmp(flight1.departureTime,
-                                    flight2.departureTime))
+            result.flights.sort(key = lambda flight: flight.departureTime)
 
         f.close()
@@ -880,5 +883,5 @@
         url = MAVA_BASE_URL + "/onlinegates_get.php"
 
-        f = urllib2.urlopen(url, timeout = 10.0)
+        f = urllib.request.urlopen(url, timeout = 10.0)
         result = Result()
         result.fleet = Fleet(f)
@@ -922,9 +925,9 @@
         gateNumber = self._gateNumber if self._gateNumber else ""
 
-        data = urllib.urlencode([("lajstrom", self._tailNumber),
+        data = urllib.parse.urlencode([("lajstrom", self._tailNumber),
                                  ("status", status),
                                  ("kapu", gateNumber)])
 
-        f = urllib2.urlopen(url, data, timeout = 10.0)
+        f = urllib.request.urlopen(url, data, timeout = 10.0)
         line = readline(f)
 
@@ -983,5 +986,5 @@
             url = "http://notams.euroutepro.com/notams.xml"
 
-            f = urllib2.urlopen(url, timeout = 10.0)
+            f = urllib.request.urlopen(url, timeout = 10.0)
             try:
                 xmlParser.parse(f)
@@ -1012,9 +1015,9 @@
               (icao.upper(),)
 
-            f = urllib2.urlopen(url, timeout = 10.0)
+            f = urllib.request.urlopen(url, timeout = 10.0)
             try:
                 data = f.read(16384)
                 while data:
-                    parser.feed(data)
+                    parser.feed(str(data))
                     data = f.read(16384)
             finally:
@@ -1023,8 +1026,8 @@
             return parser.getNOTAMs()
 
-        except Exception, e:
+        except Exception as e:
             traceback.print_exc()
-            print "mlx.web.GetNOTAMs.getPilotsWebNOTAMs: failed to get NOTAMs for '%s': %s" % \
-                  (icao, str(e))
+            print("mlx.web.GetNOTAMs.getPilotsWebNOTAMs: failed to get NOTAMs for '%s': %s" % \
+                  (icao, str(e)))
             return None
 
@@ -1042,5 +1045,5 @@
         """Perform the retrieval opf the METARs."""
         url = "http://www.aviationweather.gov/adds/dataserver_current/httpparam?"
-        data = urllib.urlencode([ ("dataSource" , "metars"),
+        data = urllib.parse.urlencode([ ("dataSource" , "metars"),
                                   ("requestType",  "retrieve"),
                                   ("format", "csv"),
@@ -1049,9 +1052,10 @@
                                   ("mostRecentForEachStation", "constraint")])
         url += data
-        f = urllib2.urlopen(url, timeout = 10.0)
+        f = urllib.request.urlopen(url, timeout = 10.0)
         try:
             result = Result()
             result.metars = {}
-            for line in iter(f.readline, ""):
+            for line in f.readlines():
+                line = str(line, "iso-8859-1")
                 if len(line)>5 and line[4]==' ':
                     icao = line[0:4]
@@ -1128,10 +1132,10 @@
         data["insdate"] = datetime.date.today().strftime("%Y-%m-%d")
 
-        postData = urllib.urlencode(data)
-        f = urllib2.urlopen(url, postData, timeout = 10.0)
+        postData = urllib.parse.urlencode(data)
+        f = urllib.request.urlopen(url, postData, timeout = 10.0)
         try:
             result = Result()
             line = f.readline().strip()
-            print "PIREP result from website:", line
+            print("PIREP result from website:", line)
             result.success = line=="OK"
             result.alreadyFlown = line=="MARVOLT"
@@ -1178,5 +1182,5 @@
     def run(self):
         """Perform the sending of the ACARS."""
-        print "Sending the online ACARS"
+        print("Sending the online ACARS")
 
         url = MAVA_BASE_URL  + "/acars2/acarsonline.php"
@@ -1204,5 +1208,5 @@
         data["event"] = acars.getEventText()
 
-        f = urllib2.urlopen(url, urllib.urlencode(data), timeout = 10.0)
+        f = urllib.request.urlopen(url, urllib.parse.urlencode(data), timeout = 10.0)
         try:
             result = Result()
@@ -1223,5 +1227,5 @@
     def run(self):
         """Perform the sending of the ACARS."""
-        print "Sending the online ACARS via JSON-RPC"
+        print("Sending the online ACARS via JSON-RPC")
 
         self._client.updateOnlineACARS(self._acars)
@@ -1243,5 +1247,5 @@
     def run(self):
         """Perform the sending of the bug report."""
-        serverProxy = xmlrpclib.ServerProxy("http://mlx.varadiistvan.hu/rpc")
+        serverProxy = xmlrpc.client.ServerProxy("http://mlx.varadiistvan.hu/rpc")
 
         result = Result()
@@ -1254,5 +1258,5 @@
         result.ticketID = serverProxy.ticket.create(self._summary, self._description,
                                                     attributes, True)
-        print "Created ticket with ID:", result.ticketID
+        print("Created ticket with ID:", result.ticketID)
         result.success = True
 
@@ -1288,5 +1292,5 @@
 
         pirepData = self._client.getPIREP(self._flightID)
-        print "pirepData:", pirepData
+        print("pirepData:", pirepData)
 
         bookedFlight = BookedFlight(self._flightID)
@@ -1512,5 +1516,5 @@
 
     def callback(returned, result):
-        print returned, unicode(result)
+        print(returned, str(result))
 
     handler = Handler()
Index: src/mlx/xplane.py
===================================================================
--- src/mlx/xplane.py	(revision 909)
+++ src/mlx/xplane.py	(revision 921)
@@ -1,7 +1,7 @@
 
-import fs
-import const
-import util
-from watchdog import Watchdog
+from . import fs
+from . import const
+from . import util
+from .watchdog import Watchdog
 
 import threading
@@ -12,4 +12,5 @@
 import codecs
 import math
+from functools import total_ordering
 
 from xplra import XPlane, MultiGetter, MultiSetter, ProtocolException
@@ -106,5 +107,5 @@
             else:
                 return False
-        except ProtocolException, e:
+        except ProtocolException as e:
             self._result = None
             return True
@@ -148,4 +149,5 @@
         return True
 
+@total_ordering
 class PeriodicRequest(object):
     """A periodic request."""
@@ -198,8 +200,15 @@
         pass
 
-    def __cmp__(self, other):
-        """Compare two periodic requests. They are ordered by their next
-        firing times."""
-        return cmp(self._nextFire, other._nextFire)
+    def __eq__(self, other):
+        """Equality comparison by the firing times"""
+        return self._nextFire == other._nextFire
+
+    def __ne__(self, other):
+        """Non-equality comparison by the firing times"""
+        return self._nextFire != other._nextFire
+
+    def __lt__(self, other):
+        """Less-than comparison by the firing times"""
+        return self._nextFire < other._nextFire
 
 class PeriodicDataRequest(PeriodicRequest):
@@ -241,6 +250,6 @@
         try:
             return fun()
-        except Exception, e:
-            print >> sys.stderr, util.utf2unicode(str(e))
+        except Exception as e:
+            print(util.utf2unicode(str(e)), file=sys.stderr)
             return None
 
@@ -312,6 +321,6 @@
             try:
                 multiGetter.execute()
-            except ProtocolException, e:
-                print "xplane.Handler._performRead: " + str(e)
+            except ProtocolException as e:
+                print("xplane.Handler._performRead: " + str(e))
                 raise
 
@@ -514,8 +523,8 @@
                 self._connected = True
                 return attempts
-            except Exception, e:
-                print "xplane.Handler._connect: connection failed: " + \
+            except Exception as e:
+                print("xplane.Handler._connect: connection failed: " + \
                       util.utf2unicode(str(e)) + \
-                      " (attempts: %d)" % (attempts,)
+                      " (attempts: %d)" % (attempts,))
                 if attempts<self.NUM_CONNECTATTEMPTS:
                     time.sleep(self.CONNECT_INTERVAL)
@@ -549,5 +558,5 @@
     def _disconnect(self):
         """Disconnect from the flight simulator."""
-        print "xplane.Handler._disconnect"
+        print("xplane.Handler._disconnect")
         if self._connected:
             try:
@@ -578,10 +587,10 @@
             try:
                 if not request.process(time):
-                    print "xplane.Handler._processRequest: X-Plane returned invalid data too many times, reconnecting"
+                    print("xplane.Handler._processRequest: X-Plane returned invalid data too many times, reconnecting")
                     needReconnect = True
             except Exception as e:
-                print "xplane.Handler._processRequest: X-Plane connection failed (" + \
+                print("xplane.Handler._processRequest: X-Plane connection failed (" + \
                       util.utf2unicode(str(e)) + \
-                      "), reconnecting (attempts=%d)." % (attempts,)
+                      "), reconnecting (attempts=%d)." % (attempts,))
                 needReconnect = True
 
@@ -804,5 +813,5 @@
 
         duration is the number of seconds to keep the message displayed."""
-        print "xplra.Simulator.sendMessage:", message
+        print("xplra.Simulator.sendMessage:", message)
         self._handler.requestShowMessage(message, duration,
                                          self._handleMessageSent,
@@ -887,5 +896,5 @@
         assert not self._monitoringRequested
 
-        print "xplra.Simulator.disconnect", closingMessage, duration
+        print("xplra.Simulator.disconnect", closingMessage, duration)
 
         self._stopNormal()
@@ -938,6 +947,6 @@
         if self._lastZuluSeconds is not None and \
            zuluSeconds<self._lastZuluSeconds:
-            print "xplane.Simulator._getTimestamp: Zulu seconds have gone backwards (%f -> %f), increasing day offset" % \
-              (self._lastZuluSeconds, zuluSeconds)
+            print("xplane.Simulator._getTimestamp: Zulu seconds have gone backwards (%f -> %f), increasing day offset" % \
+              (self._lastZuluSeconds, zuluSeconds))
             self._timestampDaysOffset += 1
 
@@ -1016,6 +1025,6 @@
             return False
 
-        print "xplane.Simulator: new data: %s, %s, %s, %s, %s, %s" % \
-              (tailnum, author, description, notes, icao, liveryPath)
+        print("xplane.Simulator: new data: %s, %s, %s, %s, %s, %s" % \
+              (tailnum, author, description, notes, icao, liveryPath))
 
         self._aircraftInfo = aircraftInfo
@@ -1140,6 +1149,7 @@
             self._handler.disconnect()
 
-    def _handleHotkeysRegistered(self, success, (id, generation)):
+    def _handleHotkeysRegistered(self, success, xxx_todo_changeme2):
         """Handle the result of the hotkeys having been written."""
+        (id, generation) = xxx_todo_changeme2
         with self._hotkeyLock:
             if success and id==self._hotkeySetID and \
@@ -1150,6 +1160,7 @@
                                                     (id, generation))
 
-    def _handleHotkeys(self, data, (id, generation)):
+    def _handleHotkeys(self, data, xxx_todo_changeme3):
         """Handle the hotkeys."""
+        (id, generation) = xxx_todo_changeme3
         with self._hotkeyLock:
             if id!=self._hotkeySetID or generation!=self._hotkeySetGeneration:
@@ -1617,6 +1628,6 @@
                               [level * self._fuelTankCapacities[index]]) )
             except:
-                print "xplane.Simulator.setFuelLevel: invalid tank constant: %d" % \
-                  (tank,)
+                print("xplane.Simulator.setFuelLevel: invalid tank constant: %d" % \
+                  (tank,))
 
         handler.requestWrite(data, self._handleFuelWritten)
@@ -1748,8 +1759,9 @@
     """Model handler for the FlyJSim Dash 8-Q400."""
     @staticmethod
-    def doesHandle(aircraft, (tailnum, author, description, notes,
-                              icao, liveryPath)):
+    def doesHandle(aircraft, xxx_todo_changeme):
         """Determine if this model handler handles the aircraft with the given
         name."""
+        (tailnum, author, description, notes,
+                              icao, liveryPath) = xxx_todo_changeme
         return aircraft.type==const.AIRCRAFT_DH8D and \
           description.find("Dash 8 Q400")!=-1 and \
@@ -1909,8 +1921,9 @@
     """Model for Felis' Tupolev Tu-154-M aircraft."""
     @staticmethod
-    def doesHandle(aircraft, (tailnum, author, description, notes,
-                              icao, liveryPath)):
+    def doesHandle(aircraft, xxx_todo_changeme1):
         """Determine if this model handler handles the aircraft with the given
         name."""
+        (tailnum, author, description, notes,
+                              icao, liveryPath) = xxx_todo_changeme1
         return aircraft.type==const.AIRCRAFT_T154 and \
           author.find("Felis")!=-1 and \
Index: nemakeinst.bat
===================================================================
--- winemakeinst.bat	(revision 916)
+++ 	(revision )
@@ -1,10 +1,0 @@
-set MSVCRDIR=c:\windows\winsxs\x86_Microsoft.VC90.CRT*9.0.21022.8*
-set GTKRTDIR=c:\Python27\Lib\site-packages\gtk-2.0\runtime
-set CEFDIR=c:\Python27\Lib\site-packages\cefpython3
-set CHROMEDRIVER=c:\tmp\chromedriver.exe
-set NSISDIR=C:\Program Files\NSIS
-set WINE=yes
-
-C:\Python27\python.exe setup.py py2exe
-
-"%NSISDIR%\makensis" mlx.nsi
