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

编译生成.exe后无窗口显示,求C++ Win32游戏开发问题排查

窗口无法弹出的问题排查与修复

核心问题分析

1. 窗口类注册缺失关键参数

原代码中WNDCLASS结构体未设置lpszClassName成员,且注释掉了相关赋值语句:

//window_class.lpszClassName = GameName;

这导致注册的窗口类没有有效的类名称,后续调用CreateWindowExW时指定的类名WindowName根本不存在,窗口创建直接失败(返回NULL),因此没有窗口弹出。

2. 未校验窗口创建结果

CreateWindowExW调用后没有检查返回值是否为NULL,无法及时发现窗口创建失败的问题,也无法定位错误原因。

3. StretchDIBits动态加载错误

StretchDIBits属于GDI32.dll的导出函数,原代码从当前进程模块(GetModuleHandle(NULL))获取该函数地址,必然失败,导致渲染逻辑无法执行(虽然这不是窗口不弹出的直接原因,但会导致修复窗口后无法显示画面)。

4. 空指针访问风险

程序启动时buffer_memory为NULL,主循环中直接访问该指针会引发崩溃,需确保WM_SIZE消息处理后才进行渲染操作。

修正后的完整代码

#include <windows.h>
#include <stdio.h> // 用于输出错误信息

bool running = true;

void* buffer_memory = nullptr;
int buffer_width = 0;
int buffer_height = 0;
BITMAPINFO buffer_bitmap_info = {};

LRESULT CALLBACK window_callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    LRESULT result = 0;

    switch (uMsg) {
        case WM_CLOSE:
        case WM_DESTROY:
            running = false;
            break;

        case WM_SIZE: {
            RECT rect;
            GetClientRect(hwnd, &rect);
            buffer_width = rect.right - rect.left;
            buffer_height = rect.bottom - rect.top;

            if (buffer_width <= 0 || buffer_height <= 0) break;

            int buffer_size = buffer_width * buffer_height * sizeof(unsigned int);
            if (buffer_memory) VirtualFree(buffer_memory, 0, MEM_RELEASE);
            buffer_memory = VirtualAlloc(0, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

            buffer_bitmap_info.bmiHeader.biSize = sizeof(buffer_bitmap_info.bmiHeader);
            buffer_bitmap_info.bmiHeader.biWidth = buffer_width;
            buffer_bitmap_info.bmiHeader.biHeight = -buffer_height; // 改为负数,确保像素从上到下绘制
            buffer_bitmap_info.bmiHeader.biPlanes = 1;
            buffer_bitmap_info.bmiHeader.biBitCount = 32;
            buffer_bitmap_info.bmiHeader.biCompression = BI_RGB;
        } break;
        default: {
            result = DefWindowProc(hwnd, uMsg, wParam, lParam);
        }
    }

    return result;
}

typedef int (WINAPI* StretchDIBitsFunc)(HDC, int, int, int, int, int, int, int, int, const VOID*, const BITMAPINFO*, UINT, DWORD);

int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
    // 创建窗口类
    WNDCLASS window_class = {};
    window_class.style = CS_HREDRAW | CS_VREDRAW;
    const wchar_t* window_class_name = L"Game Window Class";
    LPCWSTR window_title = L"Ping Pong";
    window_class.lpszClassName = window_class_name; // 必须设置类名
    window_class.lpfnWndProc = window_callback;
    window_class.hInstance = hInstance; // 补充设置实例句柄,部分系统要求必须设置

    // 注册窗口类
    if (!RegisterClass(&window_class)) {
        MessageBoxW(NULL, L"窗口类注册失败", L"错误", MB_ICONERROR);
        return 1;
    }

    // 创建窗口
    HWND window = CreateWindowExW(
        0,
        window_class_name, // 使用已注册的类名
        window_title,
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, 1280, 720,
        NULL, NULL, hInstance, NULL
    );

    if (!window) {
        MessageBoxW(NULL, L"窗口创建失败", L"错误", MB_ICONERROR);
        return 1;
    }

    HDC hdc = GetDC(window);
    // 从GDI32.dll加载StretchDIBits
    HMODULE gdi32 = GetModuleHandleW(L"gdi32.dll");
    StretchDIBitsFunc StretchDIBits = reinterpret_cast<StretchDIBitsFunc>(GetProcAddress(gdi32, "StretchDIBits"));

    while (running) {
        // 消息处理
        MSG message;
        while (PeekMessage(&message, window, 0, 0, PM_REMOVE)) {
            TranslateMessage(&message);
            DispatchMessage(&message);
        }

        // 仅当buffer_memory有效时才执行渲染逻辑
        if (buffer_memory) {
            // 填充缓冲区为橙色
            unsigned int* pixel = (unsigned int*)buffer_memory;
            for (int i = 0; i < buffer_height; i++) {
                for (int z = 0; z < buffer_width; z++) {
                    *pixel++ = 0xff5500;
                }
            }

            // 渲染到窗口
            if (StretchDIBits) {
                StretchDIBits(
                    hdc, 0, 0, buffer_width, buffer_height,
                    0, 0, buffer_width, buffer_height,
                    buffer_memory, &buffer_bitmap_info, DIB_RGB_COLORS, SRCCOPY
                );
            }
        }
    }

    ReleaseDC(window, hdc);
    if (buffer_memory) VirtualFree(buffer_memory, 0, MEM_RELEASE);
    return 0;
}

关键修改说明

  1. 补全窗口类参数:设置window_class.lpszClassName为注册的类名,同时补充hInstance成员,确保窗口类注册有效。
  2. 添加错误检查:对RegisterClass和CreateWindowExW的返回值进行校验,弹出错误提示框帮助定位问题。
  3. 修复StretchDIBits加载:从GDI32.dll加载函数,确保能正确获取函数地址。
  4. 调整位图高度为负数:biHeight设为负数时,位图像素数据会从上到下排列,符合常规绘制逻辑,避免画面倒置。
  5. 避免空指针访问:主循环中仅在buffer_memory不为空时才执行渲染操作,防止崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 20:13:09