1

I'm learning DX12 and, in the process, learning "good old Win32". i have trouble exiting the main loop and it seems related to the fact that i'm not receiving the WM_CLOSE message.

In C++, Windows 10, Console application.

#include <iostream>
#include <d3d12.h>
#include <dxgi1_4.h>
#include <tchar.h>

LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    return ::DefWindowProc(hWnd, msg, wParam, lParam);
}


int main()
{
    std::cout << "Hello World!\n";

    WNDCLASSEX wc = {
        sizeof(WNDCLASSEX),
        CS_CLASSDC,
        WndProc,
        0L, 0L,
        GetModuleHandle(NULL),
        NULL, NULL, NULL, NULL,
        _T("ker engine"),
        NULL
    };

    std::cout << "Registering Class\n";
    ::RegisterClassEx(&wc);

    std::cout << "Creating Window\n";
    HWND hwnd = ::CreateWindow(
        wc.lpszClassName,
        _T("Ker Engine DX12"),
        WS_OVERLAPPEDWINDOW,
        100, 100, 1280, 800, NULL, NULL,
        wc.hInstance, NULL
    );

    std::cout << "Show Window\n";
    ::ShowWindow(hwnd, SW_SHOWDEFAULT);

    std::cout << "Update Window\n";
    ::UpdateWindow(hwnd);

    std::cout << "Entering main loop\n";
    MSG msg;
    ZeroMemory(&msg, sizeof(msg));

    while (msg.message != (WM_QUIT))
    {
        if (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
        {
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);
            std::cout << msg.message << std::endl;
            switch (msg.message)
            {
            case WM_CLOSE:
                std::cout << "close received\n";
                ::PostQuitMessage(0);
                break;
            }
            continue;
        }

    }
    std::cout << "leaving main loop\n";

    std::cout << "Destroy Window\n";
    ::DestroyWindow(hwnd);
    std::cout << "Unregister Class\n";
    ::UnregisterClass(wc.lpszClassName, wc.hInstance);
    std::cout << "Bye\n";

    return 0;
}

When i press the X (close) red window button, the window is closed but :

  • "closed received" isn't printed
  • "leaving main loop" isn't printed.

The output is :

Entering main loop
[a lot of message code, in decimal]
160  (a lot of it) (WM_NCMOUSEMOVE)
161  (WM_NCLBUTTONDOWN)
275  (WM_TIMER)
no more output printed, i have to close the console manually.

no WM_CLOSE,or WM_DESTROY, or WM_QUIT. Between BUTTONDOW and whatever TIMER is supposed to be, there should be an event related to the fact that the windows was closed, doesn't it ?

I'm a beginner at this. I tried to search google and stackoverflow but i didn't understand if the context applied to me, or it was too specific/unrelated. it's probably a duplicate but i can't find it.

Am i losing/skiping message perhaps ? that's all i can think of.

ker2x
  • 440
  • 3
  • 11
  • What is your program doing? What are you as the user doing with the program? Are you pressing the windows close button? Please try to simplify your code into a [mcve] and show it to us. – Some programmer dude Jun 24 '20 at 11:26
  • it's not doing anything except looping and waiting for CLOSE/EXIT. As i mentionned in the post, i am moving the mouse in order to go to the close button, and press it. I don't know what the minimal reproducible example is supposed to be. isn't it already as minimal as it can possibly be ? should i remove the comment ? – ker2x Jun 24 '20 at 11:32
  • as i side note, for testing purpose, i moved the PostQuitMessage out of the condition, to send it unconditionally as soon as the application start, and the application close normally as soon as it start. but this is, of course, not what i want. :) – ker2x Jun 24 '20 at 11:34
  • 1
    The proper [mcve] would be the code in the gist link, but without the comment "links" to documentation or similar comments. Also, links to code is highly discouraged. Links can disappear, or the contents might change, possibly making the question impossible to answer. Questions needs to be self-contained. – Some programmer dude Jun 24 '20 at 11:34
  • i edited the post and the gist to remove the comments. – ker2x Jun 24 '20 at 11:38
  • full source in post, gist removed – ker2x Jun 24 '20 at 11:40
  • 2
    If you have a Console app, you don't need a message loop (unless you're doing some COM stuff or other stuff, aka: messages are not the same as for a Windowed app). If you have a Windowed app, don't try to reinvent the wheel, just start with this tutorial: https://learn.microsoft.com/en-us/windows/win32/learnwin32/your-first-windows-program – Simon Mourier Jun 24 '20 at 11:40
  • my reasoning is, as it will be a DX12 graphic application, i need a main loop in order to "do stuff" even if no events are received. According to tutorials and documentation i find here and there, this is how it's supposed to be done and so i did. – ker2x Jun 24 '20 at 11:47
  • is it related to my wm_close problem or was it just for my information ? – ker2x Jun 24 '20 at 11:50
  • 1
    hooo wait, i see. i already have this WndProc function. this is where i should put my windows event message handling, and not in the loop, right ? – ker2x Jun 24 '20 at 12:00
  • 1
    YES ! that was it ! i moved the switch in the WndProc and now it works. While the help as a little bit convoluted, it did solve my problem. thx <3 – ker2x Jun 24 '20 at 12:05

1 Answers1

1

Thanks to Simon Mourier comment and link to a tutorial, the problem was solved.

The message handling had to be done in WndProc, not in the "main loop".

I'm reposting the modified, cleaned, working, code :

#include <iostream>
#include <d3d12.h>
#include <dxgi1_4.h>
#include <tchar.h>

LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CLOSE:
        std::cout << "close received\n";
        ::PostQuitMessage(0);
        return 0;
    }
    return ::DefWindowProc(hWnd, msg, wParam, lParam);
}


int main()
{
    WNDCLASSEX wc = {
        sizeof(WNDCLASSEX),
        CS_CLASSDC,
        WndProc,
        0L, 0L,
        GetModuleHandle(NULL),
        NULL, NULL, NULL, NULL,
        _T("ker engine"),
        NULL
    };

    ::RegisterClassEx(&wc);

    HWND hwnd = ::CreateWindow(
        wc.lpszClassName,
        _T("Ker Engine DX12"),
        WS_OVERLAPPEDWINDOW,
        100, 100, 1280, 800, NULL, NULL,
        wc.hInstance, NULL
    );

    ::ShowWindow(hwnd, SW_SHOWDEFAULT);
    ::UpdateWindow(hwnd);

    MSG msg;
    ZeroMemory(&msg, sizeof(msg));
    while (msg.message != (WM_QUIT))
    {
        if (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
        {
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);
        }    
    }
    ::DestroyWindow(hwnd);
    ::UnregisterClass(wc.lpszClassName, wc.hInstance);

    return 0;
}
ker2x
  • 440
  • 3
  • 11
  • 2
    Off-topic: `PeekMessage` will busy-loop. Any reason not to use `GetMessage`? – Paul Sanders Jun 24 '20 at 12:56
  • 2
    Although the code seems to work, it still has flaws. PostQuitMessage should be used for the last window because it will stop the message loop (or code deserves a remark like "I only have one window") and it should react to WM_DESTROY, not WM_CLOSE: https://stackoverflow.com/questions/16749182/whats-the-logical-difference-between-postquitmessage-and-destroywindow – Simon Mourier Jun 24 '20 at 13:18
  • @Paul Sanders : no, no reason. i'll check. thank you. – ker2x Jun 24 '20 at 13:26
  • @simon : i do, indeed, only have one window. But i'll take it into account and modify accordingly (as soon as i'll understand the implication and differences) – ker2x Jun 24 '20 at 13:28
  • so... err... after the mainloop i call destroy. which mean i called quit before destroy. i should call destroy on wm_destroy and call quit after the loop then ? – ker2x Jun 24 '20 at 13:33
  • 1
    This might help: https://stackoverflow.com/questions/3155782/what-is-the-difference-between-wm-quit-wm-close-and-wm-destroy-in-a-windows-pr – Paul Sanders Jun 24 '20 at 13:35
  • @ker2x - You mixed things up. Just follow tutorials (bis). – Simon Mourier Jun 24 '20 at 13:36
  • yeah i quickly saw what problem it caused when i tried :D – ker2x Jun 24 '20 at 13:38
  • so i have read the link. i don't need to intercept WM_CLOSE (not for now at least) and i want to Quit on WM_DESTROY. Thx for the clarification. – ker2x Jun 24 '20 at 13:48
  • After you figure it out, you could [Accept Your Own Answers](https://stackoverflow.blog/2009/01/06/accept-your-own-answers/). – Drake Wu Jul 07 '20 at 07:04
  • @DrakeWu-MSFT thank you for the reminder. the delay before i can accept is long and then i forget :( – ker2x Jul 11 '20 at 19:24