В общем, дело такое, есть класс окна, который хорошо себя показывает, обработка внутренних сообщений, отрисовки, ресайза, и т.д. и т.п. Загвоздка заключается при попытке отобразить окно сообщения, стандартный MessageBoxW.
Окно как бы есть, но его как бы и нет, т.е. если нажать на пробел или на ENTER, то выберется выделенный Button на этом сообщении, при этом его не видно. Есть ли универсальное решение данной проблемы, или в моем случае лучше использовать новый поток для этого сообщения?
Базовый/абстрактный класс окна.
window_base.h
#pragma once
#include <windows.h>
#include <strstream>
namespace base
{
namespace interop
{
class window_base
{
public:
virtual BOOL register_window();
virtual BOOL register_window(UINT style, HICON h_icon, HCURSOR h_cursor, HBRUSH hbr_background, wchar_t* lpsz_menu_name, wchar_t* lpsz_class_name, HICON h_icon_sm);
virtual BOOL register_window(const WNDCLASSEXW* wcx);
static LRESULT CALLBACK st_win_msg_handler(HWND hwnd, UINT u_msg, WPARAM w_param, LPARAM l_param);
void set_window_title(wchar_t* lpsz_title);
void set_window_title(std::wstring lpsz_title_str);
virtual BOOL create();
virtual BOOL create(DWORD dw_styles, RECT* rect);
BOOL is_window_closed() const { return b_window_closed_; };
HWND get_window_handle() const;
BOOL is_minimized() const;
protected:
HINSTANCE h_instance_;
HWND m_hwnd_;
BOOL b_window_closed_;
wchar_t sz_class_name_[256];
wchar_t sz_window_title_[256];
explicit window_base(const HINSTANCE h_inst, const WNDCLASSEXW* wcx = nullptr) : h_instance_(nullptr), m_hwnd_(nullptr), b_window_closed_(FALSE)
{
h_instance_ = h_inst;
};
virtual LRESULT CALLBACK win_msg_handler(HWND hwnd, UINT u_msg, WPARAM w_param, LPARAM l_param) = 0;
inline static window_base *get_object_from_window(const HWND h_wnd)
{
return reinterpret_cast<window_base *>(static_cast<LONG_PTR>(GetWindowLongW(h_wnd, (-21))));
}
};
}
}
window_base.cpp
#include "window_base.h"
namespace base
{
namespace interop
{
BOOL window_base::register_window()
{
WNDCLASSEX wcx;
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = st_win_msg_handler;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = h_instance_;
wcx.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
wcx.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcx.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
wcx.lpszMenuName = nullptr;
wcx.lpszClassName = L"BaseWindow";
wcx.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);
return register_window(&wcx);
}
BOOL window_base::register_window(const UINT style, const HICON h_icon, const HCURSOR h_cursor,
const HBRUSH hbr_background,
wchar_t* lpsz_menu_name, wchar_t* lpsz_class_name, const HICON h_icon_sm)
{
WNDCLASSEX wcx;
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.style = style;
wcx.lpfnWndProc = st_win_msg_handler;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = h_instance_;
wcx.hIcon = h_icon;
wcx.hCursor = h_cursor;
wcx.hbrBackground = hbr_background;
wcx.lpszMenuName = lpsz_menu_name;
wcx.lpszClassName = lpsz_class_name;
wcx.hIconSm = h_icon_sm;
return register_window(&wcx);
}
BOOL window_base::register_window(const WNDCLASSEXW* wcx)
{
ZeroMemory(sz_class_name_, sizeof(wchar_t) * 256);
wcscpy_s(sz_class_name_, wcx->lpszClassName);
if (RegisterClassEx(wcx) == 0)
return FALSE;
return TRUE;
}
LRESULT CALLBACK window_base::st_win_msg_handler(const HWND hwnd, const UINT u_msg, const WPARAM w_param,
const LPARAM l_param)
{
if (u_msg == WM_NCCREATE)
{
SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(LPCREATESTRUCT(l_param)->lpCreateParams));
return 1;
}
window_base* p_wnd = reinterpret_cast<window_base*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
if (!p_wnd || !p_wnd->m_hwnd_)
{
return DefWindowProc(hwnd, u_msg, w_param, l_param);
}
return p_wnd->win_msg_handler(hwnd, u_msg, w_param, l_param);
}
void window_base::set_window_title(wchar_t* lpsz_title)
{
ZeroMemory(sz_window_title_, sizeof(wchar_t) * 256);
wcscpy_s(sz_window_title_, lpsz_title);
SetWindowTextW(m_hwnd_, sz_window_title_);
}
void window_base::set_window_title(std::wstring lpsz_title)
{
set_window_title(const_cast<wchar_t*>(lpsz_title.c_str()));
}
BOOL window_base::create()
{
RECT rect;
rect.top = 0;
rect.left = 0;
rect.right = 640;
rect.bottom = 480;
return create(WS_OVERLAPPEDWINDOW | WS_VISIBLE, &rect);
}
BOOL window_base::create(const DWORD dw_styles, RECT* rect)
{
m_hwnd_ = CreateWindowExW(0L, sz_class_name_, sz_window_title_, dw_styles, rect->left, rect->top, rect->right,
rect->bottom, nullptr, nullptr, h_instance_, this);
return (m_hwnd_ != nullptr);
}
HWND window_base::get_window_handle() const
{
return m_hwnd_;
}
BOOL window_base::is_minimized() const
{
return IsIconic(m_hwnd_);
}
}
}
Далее идет класс наследник, от которого могут наследоваться перегружая предоставленные методы обработки сообщений.
direct_window_base.h
#pragma once
#include "window_base.h"
#include "data_types.h"
using base::interop::window_base;
namespace base
{
namespace interop
{
class direct_window_base : public window_base
{
protected:
/**
* \brief Оконная процедура, предоставленная именно для текущего класса окна
* \param hwnd Handle окна
* \param u_msg Сообщение
* \param w_param WORD param
* \param l_param LONG param
* \return Ответ обработки сообщения
*/
LRESULT CALLBACK win_msg_handler(HWND hwnd, UINT u_msg, WPARAM w_param, LPARAM l_param) override;
public:
explicit direct_window_base(const HINSTANCE h_inst);
virtual ~direct_window_base();
virtual void on_window_close();
virtual void on_window_destroy();
virtual void on_mouse_move(POINT pos);
virtual void on_mouse_down(POINT pos);
virtual void on_mouse_up(POINT pos);
virtual void on_key_down(int key_code);
virtual void on_key_up(int key_code);
virtual void on_size_changed(RECT rect);
virtual LRESULT on_system_command(gui::window_data_t data);
virtual void on_paint(RECT rect, HDC* dc = nullptr, PAINTSTRUCT* ps = nullptr);
};
}
}
direct_window_base.cpp
#include "direct_window_base.h"
#include "data_types.h"
#if _DEBUG
#include <iostream>
#endif
namespace base
{
namespace interop
{
LRESULT CALLBACK direct_window_base::win_msg_handler(const HWND hwnd, const UINT u_msg, const WPARAM w_param,
const LPARAM l_param)
{
switch (u_msg)
{
case WM_SYSCOMMAND:
return on_system_command({ hwnd, u_msg, w_param, l_param });
case WM_CLOSE:
on_window_close();
break;
case WM_MOUSEMOVE:
on_mouse_move({LOWORD(l_param), HIWORD(l_param)});
return FALSE;
case WM_KEYDOWN:
on_key_down(unsigned long(w_param));
return TRUE;
case WM_KEYUP:
on_key_up(unsigned long(w_param));
return TRUE;
case WM_PAINT:
RECT r;
GetClientRect(hwnd, &r);
InvalidateRect(m_hwnd_, &r, false);
on_paint(r);
break;
case WM_SIZE:
RECT rect;
GetClientRect(hwnd, &rect);
on_size_changed(rect);
return TRUE;
default:
return DefWindowProcW(hwnd, u_msg, w_param, l_param);
}
return LRESULT(0);
}
direct_window_base::direct_window_base(const HINSTANCE h_inst) : window_base(h_inst)
{
}
direct_window_base::~direct_window_base()
{
}
void direct_window_base::on_window_close()
{
on_window_destroy();
}
void direct_window_base::on_window_destroy()
{
#if _DEBUG
wchar_t buffer[255];
swprintf_s(buffer, L"[module: direct_window_base address: %p] called on_window_close by address: %p", this, &direct_window_base::on_window_close);
std::wcout << buffer << std::endl;
#endif
b_window_closed_ = 1;
}
void direct_window_base::on_mouse_move(POINT pos)
{
}
void direct_window_base::on_mouse_down(POINT pos)
{
}
void direct_window_base::on_mouse_up(POINT pos)
{
}
void direct_window_base::on_key_down(int key_code)
{
}
void direct_window_base::on_key_up(int key_code)
{
}
void direct_window_base::on_size_changed(RECT rect)
{
}
LRESULT direct_window_base::on_system_command(const gui::window_data_t data)
{
return DefWindowProcW(data.hwnd, data.msg, data.wparam, data.lparam);
}
void direct_window_base::on_paint(RECT rect, HDC* dc, PAINTSTRUCT* ps)
{
}
}
}
window.h
#pragma once
#include "direct_window_base.h"
namespace base
{
enum message_box_type
{
error,
information,
warning,
question
};
enum message_box_buttons
{
ok,
yes_no,
yes_no_cancel,
retry_cancel
};
namespace controls
{
class window : public interop::direct_window_base
{
public:
explicit window(HINSTANCE h_instance, std::wstring window_title);
~window() override;
bool show() const;
void set_window_icon(HICON icon) const;
void set_window_icon_small(HICON icon) const;
RECT get_window_rect() const;
void loop();
int message_box(std::wstring message, std::wstring title, message_box_buttons mbbox_btn, message_box_type mbbox_type);
void on_mouse_move(POINT pos) override;
void on_mouse_down(POINT pos) override;
void on_mouse_up(POINT pos) override;
void on_key_down(int key_code) override;
void on_key_up(int key_code) override;
void on_size_changed(RECT rect) override;
void on_paint(RECT rect, HDC* dc, PAINTSTRUCT* ps) override;
LRESULT on_system_command(gui::window_data_t data) override;
};
}
}
window.cpp
#include "window.h"
#include <iostream>
#include "resource.h"
#include "engine.h"
namespace base
{
namespace controls
{
window::window(const HINSTANCE h_instance, const wstring window_title) : direct_window_base(h_instance)
{
if (!window_base::register_window(CS_HREDRAW | CS_VREDRAW, LoadIconW(h_instance, MAKEINTRESOURCEW(IDI_ICON1)),
LoadCursorW(nullptr, IDC_ARROW), HBRUSH(GetStockObject(NULL_BRUSH)), nullptr,
L"awgui_window_class", LoadIconW(nullptr, MAKEINTRESOURCEW(IDI_ICON1))))
{
throw exception("Unable to register window class\n");
}
RECT rect = {0,0,800,600};
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
int x = GetSystemMetrics(SM_CXSCREEN) / 2 - (rect.right - rect.left) / 2;
int y = GetSystemMetrics(SM_CYSCREEN) / 2 - (rect.bottom - rect.top) / 2;
int err = memcpy_s(&rect.left, sizeof x, &x, sizeof rect.left);
if (err == -1)
{
wcout << L"memcpy_s(&rect.left, sizeof x, &x, sizeof rect.left) failed" << endl;
}
err = memcpy_s(&rect.top, sizeof y, &y, sizeof rect.top);
if (err == -1)
{
wcout << L"memcpy_s(&rect.top, sizeof y, &y, sizeof rect.top) failed" << endl;
}
if (!window_base::create(WS_OVERLAPPEDWINDOW, &rect))
{
UnregisterClassW(sz_class_name_, h_instance_);
throw exception("Unable to create window\n");
}
const HMENU menu = GetSystemMenu(m_hwnd_, FALSE);
AppendMenuW(menu, MF_STRING, 101, L"Visit website");
set_window_title(window_title);
}
window::~window()
{
window* self = this;
engine::get_engine(&self)->release();
DestroyWindow(m_hwnd_);
UnregisterClassW(sz_class_name_, h_instance_);
}
bool window::show() const
{
return ShowWindow(m_hwnd_, SW_SHOW);
}
void window::set_window_icon(HICON icon) const
{
SendMessageW(m_hwnd_, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(icon));
SendMessageW(m_hwnd_, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(icon));
}
void window::set_window_icon_small(HICON icon) const
{
SendMessageW(m_hwnd_, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(icon));
}
RECT window::get_window_rect() const
{
RECT r;
GetClientRect(m_hwnd_, &r);
return r;
}
void window::loop()
{
MSG msg = {nullptr};
window* self = this;
while (msg.message != WM_QUIT && !is_window_closed())
{
if (PeekMessageW(&msg, m_hwnd_, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
engine::get_engine(&self)->run();
if (this->is_minimized())
{
Sleep(1);
}
}
}
int window::message_box(wstring message, wstring title,
const message_box_buttons mbbox_btn, const message_box_type mbbox_type)
{
long mb_data = 0L;
switch (mbbox_btn)
{
case ok:
mb_data |= MB_OK;
break;
case yes_no:
mb_data |= MB_YESNO;
break;
case yes_no_cancel:
mb_data |= MB_YESNOCANCEL;
break;
default: mb_data |= 0L;
}
switch (mbbox_type)
{
case error:
mb_data |= MB_ICONERROR;
break;
case information:
mb_data |= MB_ICONINFORMATION;
break;
case warning:
mb_data |= MB_ICONWARNING;
break;
case question:
mb_data |= MB_ICONQUESTION;
break;
default: mb_data |= 0;
}
return MessageBoxW(m_hwnd_, message.c_str(), title.c_str(), mb_data);
}
void window::on_mouse_move(const POINT position)
{
wchar_t buffer[255];
wsprintfW(buffer, L"[module: window address: %p] Mouse position: is x=%d y=%d", const_cast<window*>(this), position.x, position.y);
wcout << buffer << endl;
}
void window::on_mouse_down(POINT pos)
{
}
void window::on_mouse_up(POINT pos)
{
}
void window::on_key_down(const int key_code)
{
#if _DEBUG
wchar_t buffer[255];
wsprintfW(buffer, L"[module: window address: %p] Key code is down: %d", const_cast<window*>(this), key_code);
wcout << buffer << endl;
#endif
}
void window::on_key_up(const int key_code)
{
#if _DEBUG
wchar_t buffer[255];
wsprintfW(buffer, L"[module: window address: %p] Key code is up: %d", const_cast<window*>(this), key_code);
wcout << buffer << endl;
#endif
}
void window::on_size_changed(const RECT rect)
{
#if _DEBUG
wchar_t buffer[255];
wsprintfW(buffer, L"[module: window address: %p] Size is %d %d", const_cast<window*>(this), rect.right - rect.left,
rect.bottom - rect.top);
wcout << buffer << endl;
#endif
window* self = this;
engine::get_engine(&self)->resize(rect);
}
void window::on_paint(RECT rect, HDC* dc, PAINTSTRUCT* ps)
{
window* self = this;
engine::get_engine(&self)->run();
}
LRESULT window::on_system_command(const gui::window_data_t data)
{
switch (data.wparam)
{
default:
return direct_window_base::on_system_command(data);
}
//return LRESULT(0);
}
}
}
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости