プログラムはコンソールで良いが画像での確認もしたい時にウィンドウが欲しくなるので、コンソールアプリから開けるウィンドウを作成する。
#pragma once #include <Windows.h> #include <thread> class GraphicDebugWindow {
//! @brief WNDCLASSに設定するウィンドウプロシージャ static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { //CreateWindowの最後の引数で渡したthisポインタを取得 GraphicDebugWindow* This = (GraphicDebugWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA); if (!This) {//取得できなかった(ウィンドウ生成中)場合 if (message == WM_CREATE) { This = (GraphicDebugWindow*)((LPCREATESTRUCT)lParam)->lpCreateParams; if (This) { SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)This); return This->WndProc(hWnd, message, wParam, lParam); } } } else {//取得できた場合(ウィンドウ生成後) return This->WndProc(hWnd, message, wParam, lParam); } return DefWindowProc(hWnd, message, wParam, lParam); }
//メインループのスレッド std::unique_ptr<std::thread> m_mainloop; HINSTANCE hInstance; HWND m_hwnd; public: GraphicDebugWindow() {}
bool registerWindowClass() { //インスタンスハンドルの取得 hInstance = GetModuleHandle(0); WNDCLASS winc; winc.style = CS_HREDRAW | CS_VREDRAW; winc.lpfnWndProc = StaticWndProc; winc.cbClsExtra = winc.cbWndExtra = 0; winc.hInstance = hInstance; winc.hIcon = LoadIcon(NULL, IDI_APPLICATION); winc.hCursor = LoadCursor(NULL, IDC_ARROW); winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); winc.lpszMenuName = NULL; winc.lpszClassName = TEXT("SZL_TEST_GUI_WINDOW"); if (!RegisterClass(&winc)) return false; return true; }
//! @brief スレッドの内容 int MainLoop(const TCHAR* title,int posx,int posy,int width,int height) { //メッセージループはウィンドウを生成したスレッドに属していなければいけないので //CreateWindowの時点でスレッドに入っていなければならないのでここに書く m_hwnd = CreateWindow( TEXT("SZL_TEST_GUI_WINDOW"), title, WS_OVERLAPPEDWINDOW | WS_VISIBLE, posx, posy, width, height, NULL, NULL, hInstance, this ); if (m_hwnd == NULL) return 0; MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } //スレッドから抜けるときはウィンドウハンドルをnullptrにする m_hwnd = nullptr; return msg.wParam; }
//! @brief ウィンドウ作成 bool open(const TCHAR* title, int posx, int posy, int width, int height) { if (registerWindowClass() == false) return false; m_mainloop.reset(//! @brief スレッド作成 new std::thread( &GraphicDebugWindow::MainLoop, this, title, posx, posy, width, height )); return true; }
//! @brief ウィンドウを閉じたいときに呼び出す void close() { if (m_hwnd ) { SendMessage(m_hwnd, WM_DESTROY, 0, 0); } if (m_mainloop) { if (m_mainloop->joinable()) { m_mainloop->join(); } m_mainloop.reset(); } }
void join() { if (m_mainloop) { if (m_mainloop->joinable()) { m_mainloop->join(); } m_mainloop.reset(); } }
//! @brief 外にウィンドウハンドルを公開 HWND get_hwnd() {return m_hwnd;}
virtual ~GraphicDebugWindow() { close(); }
//! @brief メンバ関数版ウィンドウプロシージャ virtual LRESULT WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { PAINTSTRUCT ps; HDC hdc; switch (msg) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, msg, wp, lp); }
};
コンソールにアルファベットを入力すると、ウィンドウに表示される。
'c'または'z'で抜ける。
#include <iostream> #include "gwindbg.hpp" #pragma warning(disable:4996) int main() { GraphicDebugWindow gw; gw.open(TEXT("入力したキー表示(zで終了)"), 100, 100, 300, 300); char a = 'a'; while (a != 'z') { std::cin >> a; char text[10]; sprintf(text, "%c", a); //ウィンドウが消されていたらループを抜ける if (gw.get_hwnd() == nullptr) break; // ウィンドウを消す if (a == 'c') gw.close(); //ウィンドウの方に入力した文字を表示 HDC dc = GetDC(gw.get_hwnd()); TextOutA(dc, 0, 0, " ", 2); TextOutA(dc, 0, 0, text, 1); ReleaseDC(gw.get_hwnd(), dc); } gw.close(); std::cin >> a; }