【C++】ガンダムネットワーク大戦 エリア確認アプリケーション

ガンダムネットワーク大戦で使えるエリア確認アプリケーションを作りました
苦労した点はウィンドウを六角形に変形させたことと半透明にすることでした
このアプリケーションは前にC#/VB.netで作ってましたがフレームワークを別途インストールしないといけないという欠点がありました
このプログラムではEXEファイル単体で動きます

■注目関数
○最前面に固定
CreateWindowEx WS_EX_TOPMOSTパラメーター
○六角形にウィンドウを加工
CreatePolygonRgn
SetWindowRgn
○ウィンドウを半透明にする
CreateWindowEx WS_EX_LAYEREDパラメーター
SetLayeredWindowAttributes
○左ドラッグでウィンドウを移動
PostMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, lParam);

#include <windows.h>
#include "resource.h"
#include <objidl.h>
#include <gdiplus.h>
#include <cmath>
using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")

//六角形と中心線の描画とウィンドウを六角形にする
VOID OnPaint(HWND hwnd, HDC hdc,int height, int width)
{
	//ウィンドウを六角形にする
	static POINT pt[7];
	HRGN hrgn;
	pt[0].x = width / 2 + height / 2 * -std::cos(45);
	pt[0].y = 0;
	pt[1].x = width / 2 + width / 2 * std::cos(45);
	pt[1].y = 0;
	pt[2].x = width;
	pt[2].y = height / 2;
	pt[3].x = width / 2 + width / 2 * std::cos(45);
	pt[3].y = height;
	pt[4].x = width / 2 + width / 2 * -std::cos(45);
	pt[4].y = height;
	pt[5].x = 0;
	pt[5].y = height / 2;
	pt[6].x = width / 2 + width / 2 * -std::cos(45);
	pt[6].y = 0;
	hrgn = CreatePolygonRgn(pt, 7, ALTERNATE);
	SetWindowRgn(hwnd, hrgn, TRUE);

	//枠線(六角形)と中心線の描画
	Graphics graphics(hdc);
	Pen      pen(Color(255, 125, 125, 125), 1);//Gray
	//'縦線
	graphics.DrawLine(&pen, (int)(width / 2), 0, (int)(width / 2), (int)(height));
	//'横線
	graphics.DrawLine(&pen, 0, (int)(height / 2), (int)(width), (int)(height / 2));
	//'右斜線
	graphics.DrawLine(&pen, (int)(width / 2), (int)(height / 2), (int)(width / 2 + width / 2 * -std::cos(45)), 0);
	graphics.DrawLine(&pen, (int)(width / 2), (int)(height / 2), (int)(width / 2 + width / 2 * std::cos(45)), (int)(height));
	//'左斜線
	graphics.DrawLine(&pen, (int)(width / 2), (int)(height / 2), (int)(width / 2 + width / 2 * std::cos(45)), 0);
	graphics.DrawLine(&pen, (int)(width / 2), (int)(height / 2), (int)(width / 2 + width / 2 * -std::cos(45)), (int)(height));
	//'左上線
	graphics.DrawLine(&pen, (int)(width / 2 + width / 2 * -std::cos(45)), 0, 0, (int)(height / 2));
	//'左下線
	graphics.DrawLine(&pen, 0, (int)(height / 2), (int)(width / 2 + width / 2 * -std::cos(45)), (int)(height));
	//'右上線
	graphics.DrawLine(&pen, (int)(width / 2 + width / 2 * std::cos(45)), 0, (int)(width), (int)(height / 2));
	//'右下線
	graphics.DrawLine(&pen, (int)(width / 2 + width / 2 * std::cos(45)), height, (int)(width), (int)(height / 2));
	//'上線
	graphics.DrawLine(&pen, (int)(width / 2 + width / 2 * std::cos(45)), 0, (int)(width / 2 + width / 2 * -std::cos(45)), 0);
	//'下線
	graphics.DrawLine(&pen, (int)(width / 2 + width / 2 * std::cos(45)), (int)(height-1), (int)(width / 2 + width / 2 * -std::cos(45)), (int)(height)-1);

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
	WPARAM wParam, LPARAM lParam) {
	
	static int sw = 0;
	POINT pt;
	HMENU hmenu, hSubmenu;
	HDC hdc;
	PAINTSTRUCT ps;
	static int width = 0, height = 0;
	static int iXpos = 0, iYpos = 0;
	RECT rect;
	
	switch (message) {
	case WM_MOVE:
		iXpos = LOWORD(lParam);
		iYpos = HIWORD(lParam);
	case WM_SIZE:
		width = LOWORD(lParam);
		height = HIWORD(lParam);
		break;
	case WM_CREATE:
		SetLayeredWindowAttributes(hwnd, RGB(255, 255, 255), 120, LWA_ALPHA);
		InvalidateRect(hwnd, NULL, TRUE);
		break;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDCLOSE: //終了
			DestroyWindow(hwnd);
			break;
		case ID_R_90: //90%
			InvalidateRect(hwnd, NULL, TRUE);
			MoveWindow(hwnd, iXpos, iYpos, 778, 440, TRUE);
			break;
		case ID_R_100: //100%
			InvalidateRect(hwnd, NULL, TRUE);
			MoveWindow(hwnd, iXpos, iYpos, 867, 480, TRUE);
			break;
		case ID_R_110: //110%
			InvalidateRect(hwnd, NULL, TRUE);
			MoveWindow(hwnd, iXpos, iYpos, 955, 525, TRUE);
			break;
		case ID_R_125: //125%
			InvalidateRect(hwnd, NULL, TRUE);
			MoveWindow(hwnd, iXpos, iYpos, 1084, 600, TRUE);
			break;
		case ID_R_150: //150%
			InvalidateRect(hwnd, NULL, TRUE);
			MoveWindow(hwnd, iXpos, iYpos, 1300, 720, TRUE);
			break;
		default:
			return (DefWindowProc(hwnd, message, wParam, lParam));
		}
		break;
	case WM_RBUTTONDOWN:
		//右クリックでサブメニューを表示
		pt.x = LOWORD(lParam);
		pt.y = HIWORD(lParam);
		hmenu = LoadMenu((HINSTANCE)GetWindowLong(hwnd,-6 /*GWL_HINSTANCE*/), MAKEINTRESOURCE(IDR_MENU1));
		hSubmenu = GetSubMenu(hmenu, 0);
		ClientToScreen(hwnd, &pt);
		TrackPopupMenu(hSubmenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hwnd, NULL);
		DestroyMenu(hmenu);
		break;
	case WM_LBUTTONDOWN:
		//左ドラッグでウィンドウを移動
		PostMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, lParam);
		break;
	case WM_PAINT:
		GetClientRect(hwnd, &rect);
		hdc = BeginPaint(hwnd, &ps);
		OnPaint(hwnd, hdc, rect.bottom, rect.right); //六角形と中心線の描画
		EndPaint(hwnd, &ps);
		break;
	case WM_CLOSE:
		DestroyWindow(hwnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}
int WINAPI WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nCmdShow
) {
	HWND hWnd;
	LPCTSTR szclassName = TEXT("GNT_Area_Cpp");
	WNDCLASSEX wcex;

	GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR           gdiplusToken;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

	ZeroMemory((LPVOID)&wcex, sizeof(WNDCLASSEX));

	//ウィンドウクラスを登録
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = 0;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wcex.lpszMenuName = TEXT("IDR_MENU1");
	wcex.lpszClassName = szclassName;
	wcex.hIconSm = NULL;
	RegisterClassEx(&wcex);

	//ウィンドウ作成
	hWnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED, szclassName, 0, (WS_BORDER),
		CW_USEDEFAULT, CW_USEDEFAULT,
		867, 480,/*100%*/
		NULL, NULL, hInstance, NULL);
	SetWindowLong(hWnd, GWL_STYLE, 0);

	//ウィンドウ表示
	ShowWindow(hWnd, SW_SHOW);

	//メッセージループ
	MSG msg = {};
	while (GetMessage(&msg, NULL, 0, 0) == 1) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	GdiplusShutdown(gdiplusToken);
	return msg.wParam;
}