【Windows API】ウィンドウのクラス化
Windows APIでウィンドウを扱う必要があったので、その辺りのコードをクラス化した。
コード
#pragma once
#include <Windows.h>
#include <string>
class Window
{
public:
Window() = default;
~Window() = default;
bool Initialize(
const wchar_t* pName,
int width,
int height,
const Window* pParent = nullptr
);
void Show();
bool Update();
void Finalize();
HWND GetWindowHandle() const;
LRESULT CALLBACK RespondMessage(
HWND windowHandle,
UINT message,
WPARAM wParam,
LPARAM lParam
);
private:
bool AddClass();
void RemoveClass();
bool Create( int width, int height, HWND parentWindowHandle );
void Destroy();
bool SetClientSizeAndMoveToCenter( int width, int height );
HINSTANCE instanceHandle = nullptr;
HWND windowHandle = nullptr;
std::wstring name = L"";
};
#include "Window.h"
LRESULT CALLBACK OnReceivedMessage( HWND, UINT, WPARAM, LPARAM );
bool Window::Initialize(
const wchar_t* pName,
int width,
int height,
const Window* pParent
) {
this->instanceHandle = GetModuleHandle( nullptr );
this->name = pName;
if ( !this->AddClass() ) return false;
auto parentWindowHandle = pParent != nullptr ? pParent->windowHandle : nullptr;
if ( !this->Create( width, height, parentWindowHandle ) ) return false;
SetWindowLongPtrW( this->windowHandle, GWLP_USERDATA, reinterpret_cast<LONG>( this ));
this->SetClientSizeAndMoveToCenter( width, height );
return true;
}
void Window::Show()
{
::ShowWindow( this->windowHandle, SW_SHOW );
::UpdateWindow( this->windowHandle );
}
bool Window::Update()
{
MSG messageInfo;
if ( PeekMessage( &messageInfo, nullptr, 0, 0, PM_REMOVE ) == 0 ) return true;
if ( messageInfo.message == WM_QUIT ) return false;
::TranslateMessage( &messageInfo );
DispatchMessage( &messageInfo );
return true;
}
void Window::Finalize()
{
this->Destroy();
this->RemoveClass();
}
bool Window::AddClass()
{
WNDCLASSEXW windowClass;
windowClass.cbSize = sizeof( WNDCLASSEXW );
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = this->instanceHandle;
windowClass.hCursor = LoadCursor( nullptr, IDC_ARROW );
windowClass.hbrBackground = static_cast<HBRUSH>(::GetStockObject( WHITE_BRUSH ));
windowClass.lpszMenuName = nullptr;
windowClass.lpszClassName = this->name.c_str();
windowClass.hIcon = LoadIcon( this->instanceHandle, IDI_APPLICATION );
windowClass.hIconSm = windowClass.hIcon;
windowClass.lpfnWndProc = OnReceivedMessage;
return ::RegisterClassExW( &windowClass ) != 0;
}
void Window::RemoveClass()
{
if ( this->instanceHandle == nullptr ) return;
UnregisterClass( this->name.c_str(), this->instanceHandle );
this->instanceHandle = nullptr;
this->name = L"";
}
bool Window::Create( int width, int height, HWND parentWindowHandle )
{
auto pName = this->name.c_str();
this->windowHandle = CreateWindowW(
pName,
pName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
width,
height,
parentWindowHandle,
nullptr,
this->instanceHandle,
nullptr
);
return this->windowHandle != nullptr;
}
void Window::Destroy()
{
if ( this->windowHandle == nullptr ) return;
::DestroyWindow( this->windowHandle );
this->windowHandle = nullptr;
}
bool Window::SetClientSizeAndMoveToCenter( int width, int height )
{
RECT windowSize, clientSize;
::GetWindowRect( this->windowHandle, &windowSize );
::GetClientRect( this->windowHandle, &clientSize );
auto windowWidth = windowSize.right - windowSize.left;
auto windowHeight = windowSize.bottom - windowSize.top;
auto clientWidth = clientSize.right - clientSize.left;
auto clientHeight = clientSize.bottom - clientSize.top;
auto nonClientWidth = windowWidth - clientWidth;
auto nonClientHeight = windowHeight - clientHeight;
auto newWindowWidth = nonClientWidth + width;
auto newWindowHeight = nonClientHeight + height;
auto positionX = ::GetSystemMetrics( SM_CXSCREEN ) / 2 - newWindowWidth / 2;
auto positionY = ::GetSystemMetrics( SM_CYSCREEN ) / 2 - newWindowHeight / 2;
return ::SetWindowPos(
this->windowHandle,
nullptr,
positionX,
positionY,
newWindowWidth,
newWindowHeight,
SWP_NOZORDER
) != 0;
}
HWND Window::GetWindowHandle() const
{
return this->windowHandle;
}
LRESULT CALLBACK Window::RespondMessage( HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_DESTROY:
::PostQuitMessage( 0 );
this->windowHandle = nullptr;
this->RemoveClass();
break;
default:
return DefWindowProc( windowHandle, message, wParam, lParam );
break;
}
return 0;
}
LRESULT CALLBACK OnReceivedMessage( HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam )
{
auto pWindow = reinterpret_cast<Window*>( GetWindowLongPtr( windowHandle, GWLP_USERDATA ) );
if ( pWindow == nullptr )
{
return DefWindowProc( windowHandle, message, wParam, lParam );
}
return pWindow->RespondMessage( windowHandle, message, wParam, lParam );
}
使い方
こんな感じで使える。一応ループ内にグラフィックAPIの処理を入れる想定で作ってある。
int APIENTRY wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow )
{
auto window = Window();
window.Initialize( L"テスト", 800, 600 );
window.Show();
while ( window.Update() )
{
// グラフィックAPIの処理とか
}
window.Finalize();
return 0;
}