0

While trying to find a suitable solution to handling window messages, I came across this question here on StackOverflow:

Object oriented c++ win32?

The answers offered great solutions and my personal favourite is the accepted answer using std::map.

However, whenever I use std::map in my code that looks like this:

#include <cstdio>
#include <map>
#include <windows.h>
#include <helixirrwidgets/Window.hpp>
using namespace HelixirrWidgets;

/// ----------------------------
/// @class  Window
/// @brief  Represents a window.
/// ----------------------------
/// Inner classes:
class Window::Helper{
public:

    /// Constructors & destructors:
    Helper(void) : active(false), created_window(false), handle_instance(GetModuleHandle(NULL)), handle_window(nullptr), message({0}){
        _ms_mopopHelpers.insert({handle_window, this});
    }
    Helper(Helper const& helper_) : active(false), created_window(false), handle_instance(helper_.handle_instance), handle_window(helper_.handle_window), message(helper_.message){
        _ms_mopopHelpers.insert({handle_window, this});
    }
    Helper(Helper&& helper_) : active(false), created_window(false), handle_instance(std::move(helper_.handle_instance)), handle_window(std::move(helper_.handle_window)), message(std::move(helper_.message)){
        helper_.handle_instance = nullptr;
        helper_.handle_window = nullptr;
        _ms_mopopHelpers.insert({handle_window, this});
    }
    ~Helper(void){
        handle_instance = nullptr;
        handle_window = nullptr;
        _ms_mopopHelpers.erase(handle_window);
    }

    /// Member data:
    bool mutable active, created_window;
    HINSTANCE mutable handle_instance;
    HWND mutable handle_window;
    MSG message;

    /// Member functions (overloaded operators, assignment):
    Helper& operator=(Helper const& helper_) = default;
    Helper& operator=(Helper&& helper_) = default;

    /// Static member functions:
    static LRESULT CALLBACK handle_callback(HWND handle_window_, UINT message_, WPARAM wparam_, LPARAM lparam_){
        if(_ms_mopopHelpers.size() != 0){
            // Delegate message handling:
            return _ms_mopopHelpers[handle_window_]->_handle_callback(message_, wparam_, lparam_);
        }
        return 0;
    }

private:
    /// Member functions:
    LRESULT _handle_callback(UINT message_, WPARAM wparam_, LPARAM lparam_){
        switch(message_){
            case WM_DESTROY:
                active = false;
                DestroyWindow(handle_window);
                return 0;
            default:
                return DefWindowProc(handle_window, message_, wparam_, lparam_);
        }
    }
    /// Static member data:
    static std::map<HWND, Window::Helper*> _ms_mopopHelpers;
};
    /// Static member data:
    std::map<HWND, Window::Helper*> Window::Helper::_ms_mopopHelpers = {};
/// Constructors & destructors:
Window::Window(void) : _m_bVisible(false), _m_opHelper(new Window::Helper){

}
Window::Window(Window const& window_) = default;
Window::Window(Window&& window_) = default;
Window::Window(std::string const& name_) : _m_bVisible(false), _m_opHelper(new Window::Helper), _m_oName(name_){

}
Window::Window(std::string&& name_) : _m_bVisible(false), _m_opHelper(new Window::Helper), _m_oName(std::move(name_)){

}
Window::~Window(void) = default;
/// Member functions:
bool const& Window::active(void) const noexcept{
    return _m_opHelper->active;
}
Window& Window::save_changes(void){
    // Create and register window class:
    static bool __registered_class_window = false;
    static WNDCLASSEX __class_window = {
        sizeof(WNDCLASSEX),
        CS_HREDRAW | CS_VREDRAW,
        Window::Helper::handle_callback,
        0, 0,
        _m_opHelper->handle_instance,
        LoadIcon(_m_opHelper->handle_instance, NULL),
        LoadCursor(NULL, IDC_ARROW),
        reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)),
        NULL,
        "Helixirr Widgets Window Class Basic",
        LoadIcon(_m_opHelper->handle_instance, NULL)
    };
    if(!__registered_class_window){
        RegisterClassEx(&__class_window);
        __registered_class_window = true;
    }

    // If window hasn't been created yet:
    if(!_m_opHelper->created_window){
        _m_opHelper->created_window = true;
        _m_opHelper->handle_window = CreateWindowEx(
            0,
            "Helixirr Widgets Window Class Basic",
            _m_oName.c_str(),
            WS_OVERLAPPEDWINDOW,
            _m_uiPos[0], _m_uiPos[1],
            _m_uiSize[0], _m_uiSize[1],
            NULL, NULL, _m_opHelper->handle_instance, NULL
        );
    }
    _m_opHelper->active = true;
    return *this;
}
void Window::show(void){
    if(_m_opHelper->active){
        if(GetMessage(&_m_opHelper->message, NULL, 0, 0)){
            // Handle messages:
            TranslateMessage(&_m_opHelper->message);
            DispatchMessage(&_m_opHelper->message);

            // Handle window displaying:
            ShowWindow(_m_opHelper->handle_window, SW_SHOWDEFAULT);
            UpdateWindow(_m_opHelper->handle_window);
            return;
        }
    }
}

my window doesn't open for some reason. After cutting way all connections to std::map, window shows up again just fine. What might be causing this wierd phenomenon? It is quite hard to believe there's some kind of conflict.

Community
  • 1
  • 1
Helixirr
  • 911
  • 9
  • 18
  • First, I might ask - why make C++ wrappers for the Win32 C API when there are already plenty of good ones? i.e. qt, wxWidgets. – Reinderien Mar 20 '13 at 20:48
  • That's an excellent question, and the answer is that I want to learn to make my own wrapper. I also want my wrapper to be useful. – Helixirr Mar 20 '13 at 20:51
  • 3
    You didn't show enough code. I can't see where the window is created. I can't see much evidence of error checking. Show enough code for us to run. Don't call `DestroyWindow` from `WM_DESTROY`. It was the call to `DestroyWindow` that resulted in the `WM_DESTROY` message. And there's no conflict. There's just a bug in your code. Nothing more prosaic than that. – David Heffernan Mar 20 '13 at 20:56
  • Any suggestions, please? I don't know what's going on. – Helixirr Mar 20 '13 at 22:37
  • Raymond Chen's [Win32 C++ template](http://blogs.msdn.com/b/oldnewthing/archive/2005/04/22/410773.aspx) is hard to beat. Once you've got the basics right, you can easily expand on it. – Cody Gray - on strike Mar 20 '13 at 23:14
  • @Cody Gray: Wierd. Whenever I use the code in the callback in my code, window won't show up. std::map doesn't seem to have anything to do with it, it has to be something else. – Helixirr Mar 21 '13 at 08:14
  • OK, apparently this prevents my window from showing up: if(message_ == WM_NCCREATE){ auto const __struct = reinterpret_cast(lparam_); __helper = reinterpret_cast(__struct->lpCreateParams); __helper->handle_window = handle_window_; SetWindowLongPtr(handle_window_, GWLP_USERDATA, reinterpret_cast(__helper)); } – Helixirr Mar 21 '13 at 08:42

1 Answers1

0

Judging from your Window::show method, the problem might be that you don't have a message loop. A normal message loop looks like this:

MSG msg = {};

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

But your Window::show method only does this once, so the window might not get pumped the messages needed to actually display the window.

user1610015
  • 6,561
  • 2
  • 15
  • 18