実際のところ、Pythonでこれをやる意味は皆無ですが...
WinMainで始まるWindowsプログラムそのものをPythonでつくってみます。
以下のサンプルプログラムをPythonに直します。
Win32 APIで避けて通れないのは、独特な型と複雑な構造体です。
ウインドウメッセージの構造体MSGは、
winuser.h
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;
Pythonでは以下のようにして(自分で)定義します。
class MSG(Structure):
_fields_ = [
("hwnd", c_void_p),
("message", c_int),
("wParam", POINTER(c_int)),
("lParam", POINTER(c_int)),
("time", c_int),
("pt", POINT)]
ハンドル(HWND)はポインタなのでc_void_p、他はとりあえずc_intと考えればよいです。
WPARAM,LPARAMはc_intにするとaccess violationになったので、POINTER(c_int)としました。
POINTはWindowsで定義されている構造体です。
このようにして、必要なすべての構造体と定数を定義しておいて(ctypes_windows.py)
from ctypes_windows import *
def WindowProc(hwnd, uMsg, wParam, lParam):
if uMsg == WM_DESTROY:
PostQuitMessage(0)
return 0
elif uMsg == WM_PAINT:
ps = PAINTSTRUCT()
hdc = BeginPaint(hwnd, pointer(ps))
FillRect(hdc, pointer(ps.rcPaint), c_void_p(COLOR_WINDOW))
EndPaint(hwnd, pointer(ps))
return 0
return DefWindowProc(hwnd, uMsg, wParam, lParam)
def WinMain():
hInstance = GetModuleHandle(None)
CLASS_NAME = create_string_buffer(b"Sample Window Class")
wc = WNDCLASS()
wc.lpfnWndProc = WNDPROC(WindowProc)
wc.hInstance = hInstance
wc.lpszClassName = CLASS_NAME
RegisterClass(pointer(wc))
lpWindowName = create_string_buffer(b"Learn to Program Windows")
hwnd = CreateWindowEx(0, CLASS_NAME, lpWindowName, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
None, None, hInstance, None)
if hwnd == None:
raise Exception
ShowWindow(hwnd, SW_SHOWNORMAL)
msg = MSG()
while (GetMessage(pointer(msg), None, 0, 0)):
TranslateMessage(pointer(msg))
DispatchMessage(pointer(msg))
if __name__ == "__main__":
WinMain()
構造体と定数
ctypes_windows.py
from ctypes import *
GetModuleHandle = windll.kernel32.GetModuleHandleA
RegisterClass = windll.user32.RegisterClassA
CreateWindowEx = windll.user32.CreateWindowExA
ShowWindow = windll.user32.ShowWindow
GetMessage = windll.user32.GetMessageA
TranslateMessage = windll.user32.TranslateMessage
DispatchMessage = windll.user32.DispatchMessageA
DefWindowProc = windll.user32.DefWindowProcA
PostQuitMessage = windll.user32.PostQuitMessage
BeginPaint = windll.user32.BeginPaint
FillRect = windll.user32.FillRect
EndPaint = windll.user32.EndPaint
WNDPROC = WINFUNCTYPE(c_int, c_void_p, c_int, POINTER(c_int), POINTER(c_int))
class WNDCLASS(Structure):
_fields_ = [
("style", c_int),
("lpfnWndProc", WNDPROC),
("cbClsExtra", c_int),
("cbWndExtra", c_int),
("hInstance", c_void_p),
("hIcon", c_void_p),
("hCursor", c_void_p),
("hbrBackground", c_void_p),
("lpszMenuName", POINTER(c_char)),
("lpszClassName", POINTER(c_char))]
class POINT(Structure):
_fields_ = [
("x", c_int),
("y", c_int)]
class MSG(Structure):
_fields_ = [
("hwnd", c_void_p),
("message", c_int),
("wParam", c_int),
("lParam", c_int),
("time", c_int),
("pt", POINT)]
class RECT(Structure):
_fields_ = [
("left", c_int),
("top", c_int),
("right", c_int),
("bottom", c_int)]
class PAINTSTRUCT(Structure):
_fields_ = [
("hdc", c_void_p),
("fErase", c_int),
("rcPaint", RECT),
("fRestore", c_int),
("fIncUpdate", c_int),
("rgbReserved", c_char*32)]
WS_OVERLAPPED = 0x00000000
WS_POPUP = 0x80000000
WS_CHILD = 0x40000000
WS_MINIMIZE = 0x20000000
WS_VISIBLE = 0x10000000
WS_DISABLED = 0x08000000
WS_CLIPSIBLINGS = 0x04000000
WS_CLIPCHILDREN = 0x02000000
WS_MAXIMIZE = 0x01000000
WS_CAPTION = 0x00C00000
WS_BORDER = 0x00800000
WS_DLGFRAME = 0x00400000
WS_VSCROLL = 0x00200000
WS_HSCROLL = 0x00100000
WS_SYSMENU = 0x00080000
WS_THICKFRAME = 0x00040000
WS_GROUP = 0x00020000
WS_TABSTOP = 0x00010000
WS_MINIMIZEBOX = 0x00020000
WS_MAXIMIZEBOX = 0x00010000
WS_OVERLAPPEDWINDOW = (WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
CW_USEDEFAULT = 0x80000000
SW_SHOWNORMAL = 10
WM_CREATE = 0x0001
WM_DESTROY = 0x0002
WM_COMMAND = 0x0111
WM_PAINT = 0x000f
COLOR_WINDOW = 5