Friday, March 25, 2011

Programing Win32 with python (2.x version) and ctypes (simple sample)

What ctypes is:
ctypes is a foreign function library for Python. It provides C compatible data types, and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python.
(* www.python.org)

OK, let's test this module. We will develop "hello world" win32 application.

Here is the code:
# -*- coding: utf-8 -*-
from sys import platform, exit
from ctypes import *
from ctypes.wintypes import DWORD, HWND, HANDLE, LPCWSTR, WPARAM, LPARAM, RECT, POINT, MSG

WNDPROCTYPE = WINFUNCTYPE(c_int, HWND, c_uint, WPARAM, LPARAM)

WS_EX_APPWINDOW = 0x40000
WS_OVERLAPPEDWINDOW = 0xcf0000
WS_CAPTION = 0xc00000

SW_SHOWNORMAL = 1
SW_SHOW = 5

CS_HREDRAW = 2
CS_VREDRAW = 1

CW_USEDEFAULT = 0x80000000

WM_DESTROY = 2

WHITE_BRUSH = 0

class WNDCLASSEX(Structure):
    _fields_ = [("cbSize", c_uint),
                ("style", c_uint),
                ("lpfnWndProc", WNDPROCTYPE),
                ("cbClsExtra", c_int),
                ("cbWndExtra", c_int),
                ("hInstance", HANDLE),
                ("hIcon", HANDLE),
                ("hCursor", HANDLE),
                ("hBrush", HANDLE),
                ("lpszMenuName", LPCWSTR),
                ("lpszClassName", LPCWSTR),
                ("hIconSm", HANDLE)]

def PyWndProcedure(hWnd, Msg, wParam, lParam):
 if Msg == WM_DESTROY:
  windll.user32.PostQuitMessage(0)
 else:
  return windll.user32.DefWindowProcW(hWnd, Msg, wParam, lParam)
 return 0

WndProc = WNDPROCTYPE(PyWndProcedure)

hInst = windll.kernel32.GetModuleHandleW(0)
print(hInst)

wclassName = u'My Python Win32 Class'

wndClass = WNDCLASSEX()
wndClass.cbSize = sizeof(WNDCLASSEX)
wndClass.style = CS_HREDRAW | CS_VREDRAW
wndClass.lpfnWndProc = WndProc
wndClass.cbClsExtra = 0
wndClass.cbWndExtra = 0
wndClass.hInstance = hInst
wndClass.hIcon = 0
wndClass.hCursor = 0
wndClass.hBrush = windll.gdi32.GetStockObject(WHITE_BRUSH)
wndClass.lpszMenuName = 0
wndClass.lpszClassName = wclassName
wndClass.hIconSm = 0
print(wndClass)

regRes = windll.user32.RegisterClassExW(byref(wndClass))
print(regRes)

wname = u'My test window'

hWnd = windll.user32.CreateWindowExW(
 0,
 wclassName,
 wname,
 WS_OVERLAPPEDWINDOW | WS_CAPTION,
 CW_USEDEFAULT,
 CW_USEDEFAULT,
 300,
 300,
 0,
 0,
 hInst,
 0)
print('hWnd', hWnd)
if not hWnd:
 print('Failed to create window')
 exit(0)

print('ShowWindow', windll.user32.ShowWindow(hWnd, SW_SHOW))
print('UpdateWindow', windll.user32.UpdateWindow(hWnd))

msg = MSG()
lpmsg = pointer(msg)

print('Entering message loop')
while windll.user32.GetMessageW(lpmsg, 0, 0, 0) != 0:
 windll.user32.TranslateMessage(lpmsg)
 windll.user32.DispatchMessageW(lpmsg)

print('done.')

And here it is the "Hello world" application... :)(screenshot)

What's the point?
* as always to have fun...

Conclusions
* it was easy and fun to use ctypes in this simple scenario
* I'll try to test ctypes in more complex situations and will report back my findings

Thanks for your attention and have a good weekend!