我在谷歌上搜索了一段时间,但找不到用于创建和显示窗口的 python3 ctypes 和 Win32 API 的简单示例。请给我指出好的链接或在此处显示代码。
提前致谢!
使用 win32gui 模块及其朋友 win32api 和 win32con 最容易做到这一点。无需将自己的 ctypes 包装器写入 Windows API。最简单的 Petzold 风格的应用程序是这样的:
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()
发现了这个漂亮的小饰品,并花时间让它在 vanilla python 3.4.0 的标准库上工作:
(对于那些希望在 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())
这是一个基于 @Tcll 答案的纯
ctypes
版本,也移植到“宽”API。 原始版本无法正确处理 64 位 Python(将句柄转换为 c_int)并且使用 ANSI API,因此不再推荐。 它还为所有内容声明完整的 argtypes/restype 以帮助捕获编码错误。
如您所见,使用
pywin32
更容易。
在 Python 2.7 32 位、Python 3.6 64 位和 Python 3.8 32 位上测试。
#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())