You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinAPI中ShowWindow()无法最大化无标题栏窗口求助

问题分析与解决方案

你的窗口最大化失效主要有三个核心原因:

  1. 主窗口缺少最大化支持风格:WS_POPUP风格默认不包含最大化功能,必须显式添加WS_MAXIMIZEBOX风格,系统才会响应最大化请求。
  2. 固定窗口区域限制:你通过SetWindowRgn设置了圆角区域,即使窗口被最大化,也会被限制在该区域内,视觉上无变化。
  3. 全局HTCAPTION响应:WM_NCHITTEST直接返回HTCAPTION,导致整个窗口都被识别为标题栏,双击任意位置都会触发最大化,不符合常规交互逻辑。

修复步骤

1. 修改主窗口创建风格

添加WS_MAXIMIZEBOX,让系统允许窗口最大化:

hwnd = CreateWindowExA(WS_EX_LAYERED | WS_EX_NOINHERITLAYOUT, 
                       app_name, 
                       "main", 
                       WS_POPUP | WS_MAXIMIZEBOX,  // 添加WS_MAXIMIZEBOX
                       0, 0, 
                       w_width + 2 * border_size + corner_rounding / 2, 
                       w_height + 2 * border_size + corner_rounding / 2, 
                       NULL, NULL, hInstance, NULL);

2. 调整WM_NCHITTEST处理

仅让标题栏区域返回HTCAPTION,其他区域按默认逻辑处理:

case WM_NCHITTEST:
{
    POINT pt = { LOWORD(lp), HIWORD(lp) };
    ScreenToClient(hwnd, &pt);
    // 仅标题栏区域(高度为caption_size + border_size)视为标题栏
    if (pt.y < caption_size + border_size)
    {
        return HTCAPTION;
    }
    return DefWindowProcA(hwnd, msg, wp, lp);
}

3. 添加WM_SIZE和WM_GETMINMAXINFO处理

  • WM_GETMINMAXINFO:设置最大化时的窗口尺寸,确保铺满屏幕工作区(排除任务栏)。
  • WM_SIZE:根据窗口状态(最大化/还原)动态调整子窗口大小和窗口区域,最大化时移除圆角限制,还原时恢复。

首先将hcaption设为全局变量:

HWND hwnd;
HWND hcaption;  // 新增全局变量

然后修改WndProc:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    PAINTSTRUCT ps;
    HDC hdc;
    static HRGN mrgn = NULL;
    switch (msg)
    {
    case WM_NCLBUTTONDBLCLK:
        printf("works\n");
        // 切换最大化/还原状态
        WINDOWPLACEMENT wpState;
        wpState.length = sizeof(WINDOWPLACEMENT);
        GetWindowPlacement(hwnd, &wpState);
        ShowWindow(hwnd, 
                   wpState.showCmd == SW_MAXIMIZE ? SW_RESTORE : SW_MAXIMIZE);
        break;

    case WM_NCHITTEST:
    {
        POINT pt = { LOWORD(lp), HIWORD(lp) };
        ScreenToClient(hwnd, &pt);
        if (pt.y < caption_size + border_size)
        {
            return HTCAPTION;
        }
        return DefWindowProcA(hwnd, msg, wp, lp);
    }

    case WM_GETMINMAXINFO:
    {
        MINMAXINFO* mmi = (MINMAXINFO*)lp;
        RECT workArea;
        SystemParametersInfoA(SPI_GETWORKAREA, 0, &workArea, 0);
        // 设置最大化后的尺寸和位置(适配任务栏)
        mmi->ptMaxSize.x = workArea.right - workArea.left;
        mmi->ptMaxSize.y = workArea.bottom - workArea.top;
        mmi->ptMaxPosition.x = workArea.left;
        mmi->ptMaxPosition.y = workArea.top;
        return 0;
    }

    case WM_SIZE:
    {
        WINDOWPLACEMENT wpState;
        wpState.length = sizeof(WINDOWPLACEMENT);
        GetWindowPlacement(hwnd, &wpState);

        if (wpState.showCmd == SW_MAXIMIZE)
        {
            // 最大化时:子窗口铺满主窗口,移除圆角区域
            SetWindowPos(hcaption, NULL, 0, 0, LOWORD(lp), HIWORD(lp), SWP_NOZORDER);
            if (mrgn)
            {
                DeleteObject(mrgn);
                mrgn = NULL;
            }
            SetWindowRgn(hcaption, NULL, TRUE);
        }
        else
        {
            // 还原时:恢复子窗口位置和圆角区域
            SetWindowPos(hcaption, NULL, border_size, border_size, w_width, w_height, SWP_NOZORDER);
            if (mrgn)
                DeleteObject(mrgn);
            
            mrgn = CreateRoundRectRgn(border_size, border_size, w_width, w_height, corner_rounding, corner_rounding);
            HRGN trgn = CreateRectRgn(0, caption_size + border_size, w_width, w_height);
            CombineRgn(mrgn, mrgn, trgn, RGN_DIFF);
            DeleteObject(trgn);
            SetWindowRgn(hcaption, mrgn, TRUE);
        }
        break;
    }

    case WM_DESTROY:
        if (mrgn)
            DeleteObject(mrgn);
        PostQuitMessage(0);
        break;
    }
    return DefWindowProcA(hwnd, msg, wp, lp);
}

4. 调整WinMain中的子窗口创建

给子窗口设置控件ID,并移除重复的SetWindowRgn初始化(移到WM_SIZE中处理):

hcaption = CreateWindowExA(0, "caption_wind", NULL, WS_CHILD | WS_VISIBLE, 
                           border_size, border_size, w_width, w_height, 
                           hwnd, (HMENU)1, hInstance, NULL);
// 移除原来的SetWindowRgn代码,交给WM_SIZE初始化

最终效果

双击标题栏区域会触发窗口最大化/还原切换,最大化时窗口铺满屏幕工作区,还原时恢复圆角样式,最大化请求可以正常生效。

内容的提问来源于stack exchange,提问作者work work

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 15:45:41