Python ctypes Win32 窗口标题被截断?

2 投票
2 回答
2144 浏览
提问于 2025-04-16 14:10

我一直在尝试用Python(2.7)和ctypes模块创建一个Win32应用程序。窗口是创建出来并显示了,但窗口的标题被截断了。我只看到了'M',而不是'我的测试窗口'。我哪里做错了呢?

提前谢谢你们!

附上代码和截图:

在这里输入图片描述

# -*- 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.DefWindowProcA(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.GetMessageA(lpmsg, 0, 0, 0) != 0:
    windll.user32.TranslateMessage(lpmsg)
    windll.user32.DispatchMessageA(lpmsg)

print('done.')

2 个回答

0

如果你提供的是普通字符串,而不是unicode字符串,文本就会正常显示。

wname = '我的测试窗口'

我觉得这有点奇怪,因为你使用的是Unicode的接口(CreateWindowExW)。可能问题的根源在其他地方。

希望这能帮到你。

5

这是因为你用 CreateWindowExW 创建了一个Unicode窗口,但之后却调用了ANSI的 DefWindowProcA。你传递的字符串是Unicode格式的,而这些字符串的每隔一个字节通常都是零,因为你的文本在ASCII范围内,这就解释了你所观察到的情况。

解决办法?那就是用 DefWindowProcW 来替代。

其实,更好的解决方案是使用 win32gui,它会为你封装得更好一些。

撰写回答