使用GetWindowLongPtr获取GWL_STYLE时,并不能返回所有的窗口样式

后端开发 2026-07-09

我尝试使用GetWindowLongPtr() 获取所有样式,但遇到了一个问题:该函数返回的并不是WS_BORDER。

HWND input = CreateWindow(
    L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT,
    300, 100, 100, 20,
    hwnd, NULL, GetModuleHandle(NULL), NULL
);

LONG_PTR style = GetWindowLongPtr(input, GWL_STYLE);

在调试程序时,样式是0x50000000(只是WS_CHILD | WS_VISIBLE | ES_LEFT)。我在想,系统可能不会把WS_BORDER保存到窗口样式在内存的那一部分,而是保存在其他部分。

测试用例:

#include <windows.h>

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, wchar_t* pCmdLine, int nCmdShow) {
    WNDCLASSW wc      = {};
    wc.lpfnWndProc    = DefWindowProc;
    wc.hInstance      = hInstance;
    wc.lpszClassName  = L"Window";
    RegisterClassW(&wc);

    HWND hwnd = CreateWindow(
        L"Window", L"Test", WS_OVERLAPPEDWINDOW,
        // Size and pos
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
        NULL, NULL, hInstance, NULL
    );
    HWND input = CreateWindow(
        L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT,
        100, 220, 100, 20,
        hwnd, NULL, hInstance, NULL
    );
    ShowWindow(hwnd, nCmdShow);

    LONG_PTR style = GetWindowLongPtr(input, GWL_STYLE);

    MSG msg = {};
    while(GetMessage(&msg, NULL, 0, 0) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

解决方案

根据文档,大多数窗口样式在窗口创建后并非设计为可修改,下面列出的例外除外。如果某个样式未被列为可修改,那么设置它时的行为没有文档说明,应该避免这么做。

https://learn.microsoft.com/en-us/windows/win32/winmsg/window-styles

在窗口创建完成后,这些样式不能被修改,除非另有说明

适用于所有窗口的例外如下:

  • WS_GROUPWS_TABSTOP 可以通过 SetWindowLongPtr 设置
  • WS_VISIBLE 可以通过 ShowWindowSetWindowPos 进行修改,且
  • WS_DISABLED 可以通过 EnableWindow 进行修改。

对于编辑控件,除了所有窗口通用样式外,还有一些特定的样式:

https://learn.microsoft.com/en-us/windows/win32/controls/edit-control-styles

在这些之中,以下样式在创建后可以修改:

  • ES_LOWERCASEES_NUMBERES_OEMCONVERTES_UPPERCASEES_WANTRETURN 可以通过 SetWindowLongPtr 设置
  • ES_READONLY 可以通过发送 EM_SETREADONLY 消息来改变,配合 SendMessage 使用
  • ES_PASSWORD 可以通过发送 EM_SETPASSWORDCHAR 消息来改变,配合 SendMessage 使用

讨论

为什么通过 GetWindowLongPtrW 获取样式时,传给 CreateWindowExW 的样式看起来不可见?

对不同窗口的行为,窗口管理器提供的内容并不多——基本只包括大小、位置(包括嵌套窗口)、可见性和所有权。几乎所有其他内容,包括边框,都是由由窗口类定义的窗口过程来提供。

大多数窗口类将“大部分”功能委托给 DefWindowProcW,它为所有消息提供默认实现,以及基于样式变化的视觉行为等默认值。但这一切都可以被覆盖,因此不能就窗口的行为给出一般性的结论——它们可以随心所欲地做任何事。

若要说清楚的“构造器”意义上的东西,是通过按以下顺序发送的消息来实现的:WM_NCCREATEWM_NCCALCSIZEWM_CREATE

它们可以随心所欲地去做,并且没有义务在 GWL_STYLE 字中保存 WS_ 样式标志位。创建时保存哪些样式位,以及稍后修改样式时的行为,完全由窗口过程定义,且对每个窗口类可能不同。

通常是 WM_NCCALCSIZE 通过返回“客户端矩形”来定义边框、标题等。传递 WS_BORDER 将得到一个比实际客户端区小1 像素的客户端矩形。窗口框架由 WM_NCPAINT 绘制,通常会委托给 DefWindowProcW,但也可以被覆盖。

此外,还有消息 WM_STYLECHANGINGWM_STYLECHANGED,允许窗口对样式的变化作出响应。特别是,WM_STYLECHANGING 可以自行决定要做什么——设置的样式不保证一定是你请求的样式,这取决于窗口过程。

综合起来

没有理由认为任何行为是所有窗口类共同拥有的。

从你的测试中可以看出,传给 CreateWindowExW 的并非所有样式位都保存在 GWL_STYLE 槽中,因此也并非都能被 GetWindowLongPtrW(hWnd, GWL_STYLE) 取回。

文档并不特别清楚——它既没有明确说明它们是否全部被保存,也没有明确说明它们是否全部被保存。确实如此,因为任何窗口类都可以任意处理。

因此——你必须逐个查阅每个窗口类的文档。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章