1

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?

OnelioD
  • 7
  • 6
  • 2
    There is code missing. Can you provide a [mcve]. I'm sceptical of whether or not the arg to makeWindow is valid. I can't imagine why you would be passing a `MSG` as a reference param. My expectation would be for that to be a local variable. So, I expect your code is defective, but we can't see it. – David Heffernan May 15 '17 at 08:46
  • @DavidHeffernan I did so to see if it was the problem as a testing and I forgot to quit this part. I'll edit the code – OnelioD May 15 '17 at 09:01
  • Without a [mcve], we can only guess. Is it really so much to ask that you show us the code that you want help with? Did you even follow the link I gave you? If so, then do it again and read it very carefully. – David Heffernan May 15 '17 at 09:05

1 Answers1

0

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;
    }
}
user7860670
  • 35,849
  • 4
  • 58
  • 84
  • The standard message loop, treating `GetMessage` as a boolean, is fine in this case: https://blogs.msdn.microsoft.com/oldnewthing/20130322-00/?p=4873 – David Heffernan May 15 '17 at 09:16