It is easy to call Windows API dlls using the ctypes module with win32con defining the constant values for message identifiers and parameter flags. The demo code shows a simple but complete application that registers a window class and a Python WndProc callback function, creates the window and pumps messages.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | import win32con
import sys
from ctypes import *
WNDPROC = WINFUNCTYPE(c_long, c_int, c_uint, c_int, c_int)
class WNDCLASS(Structure):
    _fields_ = [('style', c_uint),
                ('lpfnWndProc', WNDPROC),
                ('cbClsExtra', c_int),
                ('cbWndExtra', c_int),
                ('hInstance', c_int),
                ('hIcon', c_int),
                ('hCursor', c_int),
                ('hbrBackground', c_int),
                ('lpszMenuName', c_char_p),
                ('lpszClassName', c_char_p)]
class RECT(Structure):
    _fields_ = [('left', c_long),
                ('top', c_long),
                ('right', c_long),
                ('bottom', c_long)]
class PAINTSTRUCT(Structure):
    _fields_ = [('hdc', c_int),
                ('fErase', c_int),
                ('rcPaint', RECT),
                ('fRestore', c_int),
                ('fIncUpdate', c_int),
                ('rgbReserved', c_char * 32)]
class POINT(Structure):
    _fields_ = [('x', c_long),
                ('y', c_long)]
    
class MSG(Structure):
    _fields_ = [('hwnd', c_int),
                ('message', c_uint),
                ('wParam', c_int),
                ('lParam', c_int),
                ('time', c_int),
                ('pt', POINT)]
def ErrorIfZero(handle):
    if handle == 0:
        raise WinError
    else:
        return handle
def MainWin():
    CreateWindowEx = windll.user32.CreateWindowExA
    CreateWindowEx.argtypes = [c_int, c_char_p, c_char_p, c_int, c_int, c_int, c_int, c_int, c_int, c_int, c_int, c_int]
    CreateWindowEx.restype = ErrorIfZero
    # Define Window Class
    wndclass = WNDCLASS()
    wndclass.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW
    wndclass.lpfnWndProc = WNDPROC(WndProc)
    wndclass.cbClsExtra = wndclass.cbWndExtra = 0
    wndclass.hInstance = windll.kernel32.GetModuleHandleA(c_int(win32con.NULL))
    wndclass.hIcon = windll.user32.LoadIconA(c_int(win32con.NULL), c_int(win32con.IDI_APPLICATION))
    wndclass.hCursor = windll.user32.LoadCursorA(c_int(win32con.NULL), c_int(win32con.IDC_ARROW))
    wndclass.hbrBackground = windll.gdi32.GetStockObject(c_int(win32con.WHITE_BRUSH))
    wndclass.lpszMenuName = None
    wndclass.lpszClassName = "MainWin"
    # Register Window Class
    if not windll.user32.RegisterClassA(byref(wndclass)):
        raise WinError()
    # Create Window
    hwnd = CreateWindowEx(0,
                          wndclass.lpszClassName,
                          "Python Window",
                          win32con.WS_OVERLAPPEDWINDOW,
                          win32con.CW_USEDEFAULT,
                          win32con.CW_USEDEFAULT,
                          win32con.CW_USEDEFAULT,
                          win32con.CW_USEDEFAULT,
                          win32con.NULL,
                          win32con.NULL,
                          wndclass.hInstance,
                          win32con.NULL)
    # Show Window
    windll.user32.ShowWindow(c_int(hwnd), c_int(win32con.SW_SHOWNORMAL))
    windll.user32.UpdateWindow(c_int(hwnd))
    # Pump Messages
    msg = MSG()
    pMsg = pointer(msg)
    NULL = c_int(win32con.NULL)
    
    while windll.user32.GetMessageA( pMsg, NULL, 0, 0) != 0:
        windll.user32.TranslateMessage(pMsg)
        windll.user32.DispatchMessageA(pMsg)
    return msg.wParam
    
def WndProc(hwnd, message, wParam, lParam):
    ps = PAINTSTRUCT()
    rect = RECT()
    
    if message == win32con.WM_PAINT:
        hdc = windll.user32.BeginPaint(c_int(hwnd), byref(ps))
        windll.user32.GetClientRect(c_int(hwnd), byref(rect))
        windll.user32.DrawTextA(c_int(hdc),
                                "Python Powered Windows" ,
                                c_int(-1), byref(rect), 
                                win32con.DT_SINGLELINE|win32con.DT_CENTER|win32con.DT_VCENTER)
        windll.user32.EndPaint(c_int(hwnd), byref(ps))
        return 0
    elif message == win32con.WM_DESTROY:
        windll.user32.PostQuitMessage(0)
        return 0
    return windll.user32.DefWindowProcA(c_int(hwnd), c_int(message), c_int(wParam), c_int(lParam))
if __name__=='__main__':
    sys.exit(MainWin())
 | 
The code runs on Windows98 and WindowsNT (see Comment below).
ctypes lives here: http://starship.python.net/crew/theller/ctypes/
win32con is part of win32all and lives here: http://starship.python.net/crew/mhammond/

 Download
Download Copy to clipboard
Copy to clipboard

Code runs unchanged on NT family. This code runs unchanged under the NT family of operating systems. There is no need to change it to the unicode versions of functions/structures, although it would be possible.
Discussion changed. Thanks!