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

WinAPI窗口无法显示问题求助(VS2022数字转二进制程序)

问题描述

我用Visual Studio 2022开发了一个基于WinAPI的C++程序,功能是将输入数字转换为二进制格式,但运行项目时窗口始终无法显示。我尝试修改窗口样式、调整窗口刷新位置等操作均未解决问题,附上程序代码如下:

#include "App.h"

CApp::CApp()
{
    using std::wstring;
    using std::string;

    try
    {
        this->init_native_window_obj();
        this->create_native_controls();
    }
    catch (const std::exception& e)
    {
        string expt_data = e.what();

        MessageBox(nullptr, wstring(begin(expt_data), end(expt_data)).c_str(), L"Помилка", MB_ICONERROR | MB_OK);
        ExitProcess(EXIT_FAILURE);
    }
}

void CApp::init_native_window_obj()
{
    using std::runtime_error;
    using namespace std::string_literals;

    WNDCLASSEX _wc{ sizeof(WNDCLASSEX) };
    _wc.cbClsExtra = 0;
    _wc.cbWndExtra = 0;
    _wc.hbrBackground = reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
    _wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
    _wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
    _wc.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);
    _wc.hInstance = GetModuleHandle(nullptr);
    _wc.lpfnWndProc = CApp::application_proc;
    _wc.lpszClassName = this->m_szClassName.c_str();
    _wc.lpszMenuName = nullptr;
    _wc.style = CS_HREDRAW | CS_VREDRAW;


    if (!RegisterClassEx(&_wc))
        throw runtime_error("Error, can't register main window class!"s);

    RECT _windowRC{ 0, 0, this->m_AppWidth, this->m_AppHeight };
    AdjustWindowRect(&_windowRC, WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZE, false);

    if (this->m_hWnd = CreateWindowEx(
        0,
        this->m_szClassName.c_str(),
        this->m_szAppName.c_str(),
        WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZE,
        (GetSystemMetrics(SM_CXSCREEN) - _windowRC.right) / 2,
        (GetSystemMetrics(SM_CYSCREEN) - _windowRC.bottom) / 2,
        _windowRC.right, _windowRC.bottom, nullptr, nullptr, nullptr, this
    ), !this->m_hWnd)
        throw runtime_error("Error, can't create main window");
}

void CApp::create_native_controls() 
{
    using std::runtime_error;
    using namespace::std::string_literals;

    if (this->m_hWndButton = CreateWindowEx(
        0,
        L"BUTTON",
        L"Перевести",
        WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE,
        56, 108, 238, 37, this->m_hWnd, reinterpret_cast<HMENU>(CApp::CTL_ID::CALCBUTTON_ID), nullptr, nullptr
    ), !this->m_hWndButton)
        throw runtime_error("Error, can't create button!"s);

    if (this->m_hWndEdit = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        L"EDIT",
        L"256",
        WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL,
        56, 66, 238, 24, this->m_hWnd, reinterpret_cast<HMENU>(CApp::CTL_ID::RESULTEDIT_ID), nullptr, nullptr
    ), !this->m_hWndEdit)
        throw runtime_error("Error, can't create edit!"s);

    HFONT hFont = CreateFont(18, 0, 0, 0, FW_REGULAR, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Roboto");
    SendMessage(this->m_hWndEdit, WM_SETFONT, reinterpret_cast<WPARAM>(hFont), TRUE);
    SendMessage(this->m_hWndButton, WM_SETFONT, reinterpret_cast<WPARAM>(hFont), TRUE);
}

int CApp::Run()
{
    MSG _msg{};
    ShowWindow(this->m_hWnd, SW_SHOWDEFAULT);
    UpdateWindow(this->m_hWnd);
    while (GetMessage(&_msg, nullptr, 0, 0))
    {
        TranslateMessage(&_msg);
        DispatchMessage(&_msg);
    }
    return static_cast<int>(_msg.wParam);
}

LRESULT CApp::application_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CApp* pApp;
    
    if (uMsg == WM_NCCREATE)
    {
        pApp = static_cast<CApp*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
        SetLastError(0);
        if (!SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pApp)))
        {
            if (GetLastError() != 0)
            {
                return false;
            }
        }
    }
    else
    {
        pApp = reinterpret_cast<CApp*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
    }

    if (pApp)
    {
        pApp->m_hWnd = hWnd;
        return pApp->window_proc(hWnd, uMsg, wParam, lParam);
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

LRESULT CApp::window_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_DESTROY:
        {
            PostQuitMessage(EXIT_SUCCESS);
        }
        return 0;
        case WM_COMMAND:
        {
            switch (static_cast<CApp::CTL_ID>(LOWORD(wParam)))
            {
                case CApp::CTL_ID::CALCBUTTON_ID:
                {
                    try
                    {
                        std::wstring text{};
                        text.resize(MAX_PATH);
                        GetWindowText(this->m_hWndEdit, &text[0], MAX_PATH);
                        text.erase(remove(begin(text), end(text), 0), end(text));

                        if (text.empty())
                        {
                            MessageBox(this->m_hWnd, L"Введіть число!", L"Інформація", MB_ICONINFORMATION | MB_OK);
                            break;
                        }
                        std::string binary = std::bitset<16>(std::stoi(text)).to_string();
                        text = std::wstring(begin(binary), end(binary));

                        SetWindowText(this->m_hWndEdit, text.c_str());
                    }
                    catch(...)
                    {
                        MessageBox(this->m_hWnd, L"error", MB_ICONINFORMATION | MB_OK);
                    }
                }
                break;
            }
        }
        return 0;
    }
}

CApp::~CApp() {}
问题分析与解决

核心问题

  1. 窗口过程未处理默认消息
    你的window_proc函数仅处理了WM_DESTROY和WM_COMMAND消息,其余所有消息都没有返回值,也未调用DefWindowProc处理。WinAPI窗口依赖DefWindowProc处理绘制、尺寸调整等基础消息,缺失这一步会导致窗口无法正常渲染显示。

  2. 窗口样式错误
    CreateWindowEx中使用了WS_MAXIMIZE,这是窗口显示状态标志,不属于窗口样式范畴,应该改用WS_MAXIMIZEBOX(仅添加最大化按钮),否则会导致窗口创建逻辑异常。

  3. 成员变量未初始化
    代码中用到的m_szClassName、m_szAppName、m_AppWidth、m_AppHeight等成员变量没有初始化代码。如果这些变量为空或0,会导致窗口类注册失败,或者窗口尺寸为0,自然无法看到窗口。

修复方案

1. 修复窗口过程函数

在window_proc的switch末尾添加默认分支,将未处理的消息交给DefWindowProc处理:

LRESULT CApp::window_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_DESTROY:
        {
            PostQuitMessage(EXIT_SUCCESS);
        }
        return 0;
        case WM_COMMAND:
        {
            switch (static_cast<CApp::CTL_ID>(LOWORD(wParam)))
            {
                case CApp::CTL_ID::CALCBUTTON_ID:
                {
                    // 保留原有按钮逻辑
                }
                break;
            }
        }
        return 0;
        // 处理所有未覆盖的消息
        default:
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}

2. 修正窗口样式

修改CreateWindowEx和AdjustWindowRect中的样式参数,移除WS_MAXIMIZE:

// init_native_window_obj函数中
RECT _windowRC{ 0, 0, this->m_AppWidth, this->m_AppHeight };
AdjustWindowRect(&_windowRC, WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, false);

this->m_hWnd = CreateWindowEx(
    0,
    this->m_szClassName.c_str(),
    this->m_szAppName.c_str(),
    WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
    (GetSystemMetrics(SM_CXSCREEN) - _windowRC.right) / 2,
    (GetSystemMetrics(SM_CYSCREEN) - _windowRC.bottom) / 2,
    _windowRC.right, _windowRC.bottom, nullptr, nullptr, nullptr, this
);

3. 初始化成员变量

在CApp类定义中初始化必要的成员变量:

class CApp {
private:
    // 初始化窗口类名、标题、宽高
    const std::wstring m_szClassName = L"BinaryConverterWindowClass";
    const std::wstring m_szAppName = L"数字转二进制工具";
    const int m_AppWidth = 350;
    const int m_AppHeight = 200;
    // 其他成员变量...
public:
    // 类的构造、析构、成员函数...
};

验证步骤

  1. 确保所有成员变量已正确初始化
  2. 替换修复后的代码片段
  3. 重新编译运行程序,窗口应该能正常显示并响应操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 18:11:04