Welcome, guest | Sign In | My Account | Store | Cart

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.

Python, 117 lines
  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/

2 comments

Thomas Heller 18 years, 5 months ago  # | flag

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.

Gary Eakins (author) 18 years, 5 months ago  # | flag

Discussion changed. Thanks!