编译生成.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; }
关键修改说明
- 补全窗口类参数:设置
window_class.lpszClassName为注册的类名,同时补充hInstance成员,确保窗口类注册有效。 - 添加错误检查:对
RegisterClass和CreateWindowExW的返回值进行校验,弹出错误提示框帮助定位问题。 - 修复
StretchDIBits加载:从GDI32.dll加载函数,确保能正确获取函数地址。 - 调整位图高度为负数:
biHeight设为负数时,位图像素数据会从上到下排列,符合常规绘制逻辑,避免画面倒置。 - 避免空指针访问:主循环中仅在
buffer_memory不为空时才执行渲染操作,防止崩溃。
内容的提问来源于stack exchange,提问作者user24402430
相关产品推荐
相关产品推荐

