I have googled for some time but could not find simple example of python3 ctypes and Win32 API for creating and showing window. Please point me to good link or show code here.
Thanks in advance!
I have googled for some time but could not find simple example of python3 ctypes and Win32 API for creating and showing window. Please point me to good link or show code here.
Thanks in advance!
This is most easy to do with the win32gui module and its friends, win32api and win32con. There's no need to write your own ctypes wrappers to the Windows API. The simplest Petzold style app comes out something like this:
import win32api, win32con, win32gui
class MyWindow:
def __init__(self):
win32gui.InitCommonControls()
self.hinst = win32api.GetModuleHandle(None)
className = 'MyWndClass'
message_map = {
win32con.WM_DESTROY: self.OnDestroy,
}
wc = win32gui.WNDCLASS()
wc.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW
wc.lpfnWndProc = message_map
wc.lpszClassName = className
win32gui.RegisterClass(wc)
style = win32con.WS_OVERLAPPEDWINDOW
self.hwnd = win32gui.CreateWindow(
className,
'My win32api app',
style,
win32con.CW_USEDEFAULT,
win32con.CW_USEDEFAULT,
300,
300,
0,
0,
self.hinst,
None
)
win32gui.UpdateWindow(self.hwnd)
win32gui.ShowWindow(self.hwnd, win32con.SW_SHOW)
def OnDestroy(self, hwnd, message, wparam, lparam):
win32gui.PostQuitMessage(0)
return True
w = MyWindow()
win32gui.PumpMessages()
pip install pypiwin32
–
Prelatism _winapi
, ctypes.windll.user32
, etc... just seems a bit pointless to use an extension when there's already native functionality ykno :) –
Marcelo Found this nice little trinket and took the time to get it working on nothing but the standard library of vanilla python 3.4.0:
(for those who wish to use natives over PyWin32)
http://code.activestate.com/recipes/208699-calling-windows-api-using-ctypes-and-win32con/
import sys
from ctypes import *
kernel32 = windll.kernel32
user32 = windll.user32
gdi32 = windll.gdi32
NULL = 0
CW_USEDEFAULT = -2147483648
IDI_APPLICATION = 32512
WS_OVERLAPPEDWINDOW = 13565952
CS_HREDRAW = 2
CS_VREDRAW = 1
IDC_ARROW = 32512
WHITE_BRUSH = 0
SW_SHOWNORMAL = 1
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():
global NULL
CreateWindowEx = 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 = CS_HREDRAW | CS_VREDRAW
wndclass.lpfnWndProc = WNDPROC(WndProc)
wndclass.cbClsExtra = wndclass.cbWndExtra = 0
wndclass.hInstance = kernel32.GetModuleHandleA(c_int(NULL))
wndclass.hIcon = user32.LoadIconA(c_int(NULL), c_int(IDI_APPLICATION))
wndclass.hCursor = user32.LoadCursorA(c_int(NULL), c_int(IDC_ARROW))
wndclass.hbrBackground = gdi32.GetStockObject(c_int(WHITE_BRUSH))
wndclass.lpszMenuName = None
wndclass.lpszClassName = b"MainWin"
# Register Window Class
if not user32.RegisterClassA(byref(wndclass)):
raise WinError()
# Create Window
hwnd = CreateWindowEx(0,
wndclass.lpszClassName,
b"Python Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
wndclass.hInstance,
NULL)
# Show Window
user32.ShowWindow(c_int(hwnd), c_int(SW_SHOWNORMAL))
user32.UpdateWindow(c_int(hwnd))
# Pump Messages
msg = MSG()
pMsg = pointer(msg)
NULL = c_int(NULL)
while user32.GetMessageA( pMsg, NULL, 0, 0) != 0:
user32.TranslateMessage(pMsg)
user32.DispatchMessageA(pMsg)
return msg.wParam
WM_PAINT = 15
WM_DESTROY = 2
DT_SINGLELINE = 32
DT_CENTER = 1
DT_VCENTER = 4
def WndProc(hwnd, message, wParam, lParam):
ps = PAINTSTRUCT()
rect = RECT()
if message == WM_PAINT:
hdc = user32.BeginPaint(c_int(hwnd), byref(ps))
user32.GetClientRect(c_int(hwnd), byref(rect))
user32.DrawTextA(c_int(hdc),
b"Python Powered Windows" ,
c_int(-1), byref(rect),
DT_SINGLELINE|DT_CENTER|DT_VCENTER)
user32.EndPaint(c_int(hwnd), byref(ps))
return 0
elif message == WM_DESTROY:
user32.PostQuitMessage(0)
return 0
return user32.DefWindowProcA(c_int(hwnd), c_int(message), c_int(wParam), c_int(lParam))
if __name__=='__main__':
sys.exit(MainWin())
OSError: [WinError 87] Wrong Parameter.
(translated from German). This seems to be related to the line raise WinError()
but the actual problem then is that user32.RegisterClassA(wndclass)
returns false
. –
Generalist wndclass.lpszClassName = "MainWin" TypeError: bytes or integer address expected instead of str instance
–
Thanet Here's a pure ctypes
version based on the @Tcll answer ported to "wide" APIs as well. The original version didn't handle 64-bit Python correctly (casting handles to c_int) and was using the ANSI APIs, which isn't recommended anymore. It also declares full argtypes/restype for everything to help catch coding errors.
As you can see, it's much easier to use pywin32
instead.
Tested on Python 2.7 32-bit, Python 3.6 64-bit and Python 3.8 32-bit.
#coding:utf8
from __future__ import unicode_literals
import sys
import ctypes as ct
import ctypes.wintypes as w # ctypes has many pre-defined Windows types
def errcheck(result, func, args):
if result is None or result == 0:
raise ct.WinError(ct.get_last_error())
return result
def minusonecheck(result, func, args):
if result == -1:
raise ct.WinError(ct.get_last_error())
return result
# Missing from ctypes.wintypes...
LRESULT = ct.c_int64
HCURSOR = ct.c_void_p
WNDPROC = ct.WINFUNCTYPE(LRESULT, w.HWND, w.UINT, w.WPARAM, w.LPARAM)
def MAKEINTRESOURCE(x):
return w.LPCWSTR(x)
class WNDCLASS(ct.Structure):
_fields_ = (('style', w.UINT),
('lpfnWndProc', WNDPROC),
('cbClsExtra', ct.c_int),
('cbWndExtra', ct.c_int),
('hInstance', w.HINSTANCE),
('hIcon', w.HICON),
('hCursor', HCURSOR),
('hbrBackground', w.HBRUSH),
('lpszMenuName', w.LPCWSTR),
('lpszClassName', w.LPCWSTR))
class PAINTSTRUCT(ct.Structure):
_fields_ = (('hdc', w.HDC),
('fErase', w.BOOL),
('rcPaint', w.RECT),
('fRestore', w.BOOL),
('fIncUpdate', w.BOOL),
('rgbReserved', w.BYTE * 32))
kernel32 = ct.WinDLL('kernel32', use_last_error=True)
GetModuleHandle = kernel32.GetModuleHandleW
GetModuleHandle.argtypes = w.LPCWSTR,
GetModuleHandle.restype = w.HMODULE
GetModuleHandle.errcheck = errcheck
user32 = ct.WinDLL('user32', use_last_error=True)
CreateWindowEx = user32.CreateWindowExW
CreateWindowEx.argtypes = w.DWORD, w.LPCWSTR, w.LPCWSTR, w.DWORD, ct.c_int, ct.c_int, ct.c_int, ct.c_int, w.HWND, w.HMENU, w.HINSTANCE, w.LPVOID
CreateWindowEx.restype = w.HWND
CreateWindowEx.errcheck = errcheck
LoadIcon = user32.LoadIconW
LoadIcon.argtypes = w.HINSTANCE, w.LPCWSTR
LoadIcon.restype = w.HICON
LoadIcon.errcheck = errcheck
LoadCursor = user32.LoadCursorW
LoadCursor.argtypes = w.HINSTANCE, w.LPCWSTR
LoadCursor.restype = HCURSOR
LoadCursor.errcheck = errcheck
RegisterClass = user32.RegisterClassW
RegisterClass.argtypes = ct.POINTER(WNDCLASS),
RegisterClass.restype = w.ATOM
RegisterClass.errcheck = errcheck
ShowWindow = user32.ShowWindow
ShowWindow.argtypes = w.HWND, ct.c_int
ShowWindow.restype = w.BOOL
UpdateWindow = user32.UpdateWindow
UpdateWindow.argtypes = w.HWND,
UpdateWindow.restype = w.BOOL
UpdateWindow.errcheck = errcheck
GetMessage = user32.GetMessageW
GetMessage.argtypes = ct.POINTER(w.MSG), w.HWND, w.UINT, w.UINT
GetMessage.restype = w.BOOL
GetMessage.errcheck = minusonecheck
TranslateMessage = user32.TranslateMessage
TranslateMessage.argtypes = ct.POINTER(w.MSG),
TranslateMessage.restype = w.BOOL
DispatchMessage = user32.DispatchMessageW
DispatchMessage.argtypes = ct.POINTER(w.MSG),
DispatchMessage.restype = LRESULT
BeginPaint = user32.BeginPaint
BeginPaint.argtypes = w.HWND, ct.POINTER(PAINTSTRUCT)
BeginPaint.restype = w.HDC
GetClientRect = user32.GetClientRect
GetClientRect.argtypes = w.HWND, ct.POINTER(w.RECT)
GetClientRect.restype = w.BOOL
GetClientRect.errcheck = errcheck
DrawText = user32.DrawTextW
DrawText.argtypes = w.HDC, w.LPCWSTR, ct.c_int, ct.POINTER(w.RECT), w.UINT
DrawText.restype = ct.c_int
EndPaint = user32.EndPaint
EndPaint.argtypes = w.HWND, ct.POINTER(PAINTSTRUCT)
EndPaint.restype = w.BOOL
PostQuitMessage = user32.PostQuitMessage
PostQuitMessage.argtypes = ct.c_int,
PostQuitMessage.restype = None
DefWindowProc = user32.DefWindowProcW
DefWindowProc.argtypes = w.HWND, w.UINT, w.WPARAM, w.LPARAM
DefWindowProc.restype = LRESULT
gdi32 = ct.WinDLL('gdi32', use_last_error=True)
GetStockObject = gdi32.GetStockObject
GetStockObject.argtypes = ct.c_int,
GetStockObject.restype = w.HGDIOBJ
CW_USEDEFAULT = ct.c_int(0x80000000).value
IDI_APPLICATION = MAKEINTRESOURCE(32512)
WS_OVERLAPPED = 0x00000000
WS_CAPTION = 0x00C00000
WS_SYSMENU = 0x00080000
WS_THICKFRAME = 0x00040000
WS_MINIMIZEBOX = 0x00020000
WS_MAXIMIZEBOX = 0x00010000
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
assert WS_OVERLAPPEDWINDOW == 0x00CF0000
CS_HREDRAW = 2
CS_VREDRAW = 1
IDC_ARROW = MAKEINTRESOURCE(32512)
WHITE_BRUSH = 0
SW_SHOWNORMAL = 1
WM_PAINT = 15
WM_DESTROY = 2
DT_SINGLELINE = 32
DT_CENTER = 1
DT_VCENTER = 4
def MainWin():
# Define Window Class
wndclass = WNDCLASS()
wndclass.style = CS_HREDRAW | CS_VREDRAW
wndclass.lpfnWndProc = WNDPROC(WndProc)
wndclass.cbClsExtra = 0
wndclass.cbWndExtra = 0
wndclass.hInstance = GetModuleHandle(None)
wndclass.hIcon = LoadIcon(None, IDI_APPLICATION)
wndclass.hCursor = LoadCursor(None, IDC_ARROW)
wndclass.hbrBackground = GetStockObject(WHITE_BRUSH)
wndclass.lpszMenuName = None
wndclass.lpszClassName = 'MainWin'
# Register Window Class
RegisterClass(ct.byref(wndclass))
# Create Window
hwnd = CreateWindowEx(0,
wndclass.lpszClassName,
'Python Window',
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
None,
None,
wndclass.hInstance,
None)
# Show Window
user32.ShowWindow(hwnd, SW_SHOWNORMAL)
user32.UpdateWindow(hwnd)
# Pump Messages
msg = w.MSG()
while GetMessage(ct.byref(msg), None, 0, 0) != 0:
TranslateMessage(ct.byref(msg))
DispatchMessage(ct.byref(msg))
return msg.wParam
def WndProc(hwnd, message, wParam, lParam):
ps = PAINTSTRUCT()
rect = w.RECT()
if message == WM_PAINT:
hdc = BeginPaint(hwnd, ct.byref(ps))
GetClientRect(hwnd, ct.byref(rect))
DrawText(hdc,
'Python Powered Windows 你好吗?',
-1, ct.byref(rect),
DT_SINGLELINE|DT_CENTER|DT_VCENTER)
EndPaint(hwnd, ct.byref(ps))
return 0
elif message == WM_DESTROY:
PostQuitMessage(0)
return 0
return DefWindowProc(hwnd, message, wParam, lParam)
if __name__=='__main__':
sys.exit(MainWin())
pywin32
usually doesn't run more than once after installation (it can't find itself), the best way to install pywin32
is to install Anaconda which comes with a proper package that works repeatedly. –
Marcelo © 2022 - 2024 — McMap. All rights reserved.