c++ - WIN32 多个窗口

标签 c++ winapi

我试图显示 3 个窗口,但无法创建窗口 2,我不确定为什么。它创建了第一个窗口,我对另外两个窗口做了同样的事情。

这是代码:

#include <Windows.h>

// Store handles to the main window and application instance globally.
HWND      ghMainWnd = 0;
HWND      ghSecdWnd = 0;
HWND      ghThrdWnd = 0;
HINSTANCE ghAppInst = 0;

//========================================================================================
// WINDOW 1
// Step 1: Define and implement the window procedure.
LRESULT CALLBACK
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

    switch( msg )
    {
    // Handle left mouse button click message.
    case WM_LBUTTONDOWN:
        MessageBox(hWnd, "Left Mouse Button Click", "Message", MB_OK);
        return 0;

    // Handle key down message.
    case WM_KEYDOWN:
        if( wParam == VK_ESCAPE )
            if( MessageBox(hWnd, "Are you sure?", "Quit", MB_YESNO) == IDYES )
                DestroyWindow(ghMainWnd);
        return 0;

    // Handle destroy window message.
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    // Forward any other messages we didn't handle to the default window procedure.
    return DefWindowProc(hWnd, msg, wParam, lParam);

}
//========================================================================================
// WINDOW 2
//========================================================================================
LRESULT CALLBACK
WndProc2(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

    switch( msg )
    {
    // Handle down arrow pressed.
    case WM_KEYDOWN:
        if( wParam == VK_DOWN )
            MessageBox(hWnd, "Down arrow pressed 2.", "Information", MB_OK);
        return 0;
    case WM_LBUTTONDOWN:
        MessageBox(hWnd, "Window 2", "Window 2", MB_OK);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}
//========================================================================================
// WINDOW 3
//========================================================================================
LRESULT CALLBACK
WndProc3(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

    switch( msg )
    {
    // Handle down arrow pressed.
    case WM_KEYDOWN:
        if( wParam == VK_DOWN )
            MessageBox(hWnd, "Down arrow pressed 3.", "Information", MB_OK);
        return 0;
    case WM_LBUTTONDOWN:
        MessageBox(hWnd, "Window 3", "Window 3", MB_OK);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

// WinMain: Entry point for windows application.
int WINAPI
    WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR cmdLine, int showCmd)
{

    // Save handle to application instance.
    ghAppInst = hInstance;

    // Step 2: Fill out a WNDCLASS instance.
    WNDCLASS wc;
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = ghAppInst;
    wc.hIcon         = ::LoadIcon(0, IDI_APPLICATION);
    wc.hCursor       = ::LoadCursor(0, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName  = 0;
    wc.lpszClassName = "MyWndClassName";

    // Window 2
    WNDCLASS wc2;
    wc2.style         = CS_HREDRAW | CS_VREDRAW;
    wc2.lpfnWndProc   = WndProc2;
    wc2.cbClsExtra    = 0;
    wc2.cbWndExtra    = 0;
    wc2.hInstance     = ghAppInst;
    wc.hIcon          = ::LoadIcon(0, IDI_APPLICATION);
    wc2.hCursor       = ::LoadCursor(0, IDC_ARROW);
    wc2.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
    wc2.lpszMenuName  = 0;
    wc2.lpszClassName = "MyWndClassTwo";

    // Window 3
    WNDCLASS wc3;
    wc3.style         = CS_HREDRAW | CS_VREDRAW;
    wc3.lpfnWndProc   = WndProc3;
    wc3.cbClsExtra    = 0;
    wc3.cbWndExtra    = 0;
    wc3.hInstance     = ghAppInst;
    wc3.hIcon         = ::LoadIcon(0, IDI_APPLICATION);
    wc3.hCursor       = ::LoadCursor(0, IDC_ARROW);
    wc3.lpszMenuName  = 0;
    wc3.lpszClassName = "MyWndClassThree";


    // Step 3: Register with WNDCLASS instance with windows.
    RegisterClass( &wc );
    RegisterClass( &wc2 );
    RegisterClass( &wc3 );

    // Step 4: Create the window, and save the handle in global window handle variable ghMainWnd.
    ghMainWnd = ::CreateWindow("MyWndClassName",  "Window 1", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, 0,   0,   500, 500, 0, 0, ghAppInst, 0);
    ghSecdWnd = ::CreateWindow("MyWndClassTwo",   "Window 2", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, 510, 0,   500, 500, 0, 0, ghAppInst, 0);
    ghThrdWnd = ::CreateWindow("MyWndClassThree", "Window 3", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, 0,   510, 500, 500, 0, 0, ghAppInst, 0);

    if( ghMainWnd == 0 )
    {
        ::MessageBox(0, "Create Window 1 - Failed", 0, 0);
        return false;
    }

    if( ghSecdWnd == 0 )
    {
        ::MessageBox(0, "Create Window 2 - Failed", 0, 0);
        return false;
    }

    if( ghThrdWnd == 0 )
    {
        ::MessageBox(0, "Create Window 3 - Failed", 0, 0);
        return false;
    }

    // Step 5: Show and update the window.
    ShowWindow(ghMainWnd, showCmd);
    UpdateWindow(ghMainWnd);

    ShowWindow(ghSecdWnd, showCmd);
    UpdateWindow(ghSecdWnd);

    ShowWindow(ghThrdWnd, showCmd);
    UpdateWindow(ghThrdWnd);

    // Step 6: Enter the message loop and don't quit until a WM_QUIT message is received.
    MSG msg;
    ZeroMemory(&msg, sizeof(MSG));

    while( GetMessage(&msg, 0, 0, 0) )
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // Return exit code back to operating system.
    return (int)msg.wParam;

}

它不会抛出任何错误,但在 ghSecdWnd == 0 上它会显示该错误消息。

最佳答案

有两个问题:一个是您遇到的问题,另一个是窗口 3 中的问题。

调用GetLastError()创建第二个窗口之后(但在创建第三个窗口之前)结果为 "Cannot find the window class." 。查看类设置,您已完成以下操作:

wc.hIcon = ::LoadIcon(0, IDI_APPLICATION);

你实际需要的是设置wc2的图标。甚至检查 RegisterClass 的返回值当您注册第二类时,会导致 "The parameter is incorrect." 错误,表明 wc2 有问题。它也是代码中捕获错误的较早位置,这总是一件好事。


其次,第三个窗口有问题。你还没有设置背景画笔。将此行添加到 wc3设置:

wc3.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);

您应该始终检查文档,以了解函数在失败时会执行哪些操作,并采取适当的措施。例如,如果 CreateWindow失败,返回值为NULL ,您可以调用GetLastError获取更多信息。您应该针对每个功能执行此操作。以下是 Window 2 的两个主要函数的示例。请记住其他函数,例如 GetStockObject ,也可能失败。

if (!RegisterClass(&wc2)) { //returns 0 if failed
    std::cout << "Failed to register class: ";
    std::cout << GetLastError() << '\n'; //or however you want to show it
}

if (!(ghSecdWnd = CreateWindow( /*...*/)) { //or ghSecdWnd = ...; if (!ghSecdWnd)
    std::cout << "Failed to create window: ";
    std::cout << GetLastError() << '\n'; //look at FormatMessage for a message
}

首先,查看 RegisterClass ,您会在返回值下看到,失败时返回 0,并表明您可以调用 GetLastError()以获得扩展的错误信息,所以我输出它。 CreateWindow 说的是一样的,但它是 NULL相反,因为 HWND是一个指针。您可以获取收到的错误代码并根据 MSDN System Error Codes 检查它们。文章,或使用 FormatMessage FORMAT_MESSAGE_FROM_SYSTEM为您做到这一点。

关于c++ - WIN32 多个窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13407455/

相关文章:

c++ - 函数返回在另一个类中定义的枚举(致命链接错误)

c# - 如何创建仅允许访问 C++ 中特定用户帐户的手动重置事件?

delphi - DeferWindowPos 是否与 VCL 配合良好?

c++ - Exe 不能在旧版本的 Windows 上运行

c++ - winapi - SetLayeredWindowAttributes with LWA_COLORKEY 仅将像素设置为完全不透明或完全透明?

sql-server - 无法使用SQL Server ODBC驱动程序执行同义词存储过程;与OLEDB一起使用

c++ - 每个 cpp 的 nginx 语法高亮显示,无需人工交互

c++ - (++i) 和 (i++) 的区别

c++ - 错误: use of deleted function ‘std::atomic<_Tp>::atomic() [with _Tp = node]’

c++ - 从 C++ 中的抽象类继承