c++ Win32 Api GetMessage closing program inside thread

1.3k views Asked by At

I'm building a interface using the win32 api and I wanted to manage all the suff in another class with a thread to keep doing work in the main. I have this code:

WindowManager.h

class UIManager::WindowManager {
private:
    //Class data
    HINSTANCE hInstance;
    WNDCLASSEX winClass; /* Data structure for the windowclass */
    MSG msg;
    HWND hwnd;
    //Window Data
    LPCSTR wiName;
    int startX = 250;
    int startY = 150;
    int endX = 544;
    int endY = 375;
    //Private managers
    void makeWindow();
public:
    WindowManager(HINSTANCE & hInstance, std::string wiName = "Window Name");
    void show();
};

WindowManager.c (I use bind because I have the class inside a namespace and that is the only way I found that thread allows me to compile instead of throwing an error)

#include "WindowManager.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

//Private
//
void UIManager::WindowManager::makeWindow()
{
    int ms = GetMessage(&msg, 0, 0, 0); //I do this to see if it gets to
    while (GetMessage(&msg, NULL, 0, 0)) { //this part, but never happens
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

//Public
//
UIManager::WindowManager::WindowManager(HINSTANCE & hInstance, std::string wiName)
{
    this->wiName = wiName.c_str();
    this->hInstance = hInstance;
    winClass.cbSize = sizeof(winClass);
    winClass.hInstance = hInstance;
    winClass.lpszClassName = this->wiName;
    winClass.lpfnWndProc = WndProc; //Execution callback
    //Load default editable ellements
    winClass.hCursor = LoadCursor(0, IDC_ARROW);        /*Default*/
    winClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);   /*Default*/     //Alt+Tab Dialog
    winClass.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
    winClass.lpszMenuName = NULL;                       /* No menu */
    RegisterClassEx(&winClass);

    //Create Window
    hwnd = CreateWindowEx(
        0,
        this->wiName,           /* Title Class */
        this->wiName,           /* Title Text */
        WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPEDWINDOW,
        startX,                         /* X Start */
        startY,                         /* Y Start */
        endX,                           /* The programs width */
        endY,                           /* and height in pixels */
        HWND_DESKTOP,                   /* The window is a child-window to desktop */
        NULL,                           /* No menu */
        hInstance,              /* Program Instance handler */
        NULL
    );
    SetWindowPos(hwnd, 0, 0, 0, 20, 20, 0);
}

void UIManager::WindowManager::show()
{
    std::thread listener(std::bind(&WindowManager::makeWindow, this));
    listener.detach();
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:
    { //This part is executed
        //...blablabla
        break;
    }

    case WM_COMMAND:
    {//This part is never executed
        //...blablabla
        break;
    }

    case WM_DESTROY:
    {//This part is never executed
        //...blabla
        PostQuitMessage(0);
        break;
    }
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

The window execute and show properly and even execute WM_CREATE, but when the "GetMessage" is executed it instantly end the program without throwing any error or something like that.

I added an int with the value of the GetMessage to see if it gets to the "while" in debug mode but it happens. Is there a way to see the error that may be throwing or prevent it from closing the program? Or is it that I'm doing wrong calling "GetMessage" from inside a thread?

1

There are 1 answers

1
user7860670 On BEST ANSWER

your code has several problems:

  • You create window in one thread, but try to run meesage loop in another thread. GetMessage only handles messages of windows belonging to the calling thread.
  • You never wait for background thread processing messages and instead detach from it and continue execution in main thread probably ending application.
  • You don't inspect the value returned by GetMessage and use it as boolean.

If you want to make background ui thread you need to move all window creation code there and call join on thread. And message loop should look like this:

::MSG msg;
for(;;)
{
    auto const res{::GetMessage(&msg, NULL, 0, 0))};
    if(0 < res)
    {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
    else if(0 == res)
    {   //  PostQuitMessage was called...
        break;
    }
    else
    {   //  an error occurred...
        break;
    }
}