このブログは hack.jp に移転しました。5秒後に hack.jp に移動します。

未知の破片

小さなWindowsのプログラムを書いています。

現在の時刻を色の値(RGB)に変換してウィンドウの枠を塗りつぶすプログラムです。時間によって色がコクコクと変わります。

colorclock

時刻からRGB値への変換式は下記の通りです。

時間 / 24 x 255 → 赤色値 (0 ~ 255)

分 / 60 x 255 → 緑色 (0 ~ 255)

秒 / 60 x 255 → 青色 (0 ~ 255)

プロジェクトのダウンロード

#pragma comment(lib,"dwmapi")
#include <windows.h>

TCHAR szClassName[] = TEXT("Window");

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	static HFONT hFont;
	switch (msg)
	{
	case WM_CREATE:
		hFont = CreateFont(64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TEXT("Consolas"));
		SetTimer(hWnd, 0x1234, 1000, 0);
		break;
	case WM_TIMER:
		InvalidateRect(hWnd, 0, 1);
		break;
	case WM_ERASEBKGND:
	{
		SYSTEMTIME st;
		GetLocalTime(&st);
		const BYTE red = (BYTE)(st.wHour / 24.0 * 255.0);
		const BYTE green = (BYTE)(st.wMinute / 60.0 * 255.0);
		const BYTE blue = (BYTE)(st.wSecond / 60.0 * 255.0);
		RECT rect;
		GetClientRect(hWnd, &rect);
		const HFONT hOldFont = (HFONT)SelectObject((HDC)wParam, hFont);
		const COLORREF OldTextColor = SetTextColor((HDC)wParam, RGB(255, 255, 255));
		const COLORREF OldBkColor = SetBkColor((HDC)wParam, RGB(red, green, blue));
		TCHAR szText[7];
		wsprintf(szText, TEXT("%02X%02X%02X"), red, green, blue);
		SIZE size;
		GetTextExtentPoint32((HDC)wParam, szText, lstrlen(szText), &size);
		ExtTextOut((HDC)wParam, (rect.right - size.cx) / 2, (rect.bottom - size.cy) / 2, ETO_OPAQUE, &rect, szText, 6, 0);
		SetBkColor((HDC)wParam, OldTextColor);
		SetBkColor((HDC)wParam, OldBkColor);
		SelectObject((HDC)wParam, hOldFont);
	}
	return 1;
	case WM_DESTROY:
		KillTimer(hWnd, 0x1234);
		DeleteObject(hFont);
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, msg, wParam, lParam);
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR pCmdLine, int nCmdShow)
{
	MSG msg;
	WNDCLASS wndclass = {
		0,
		WndProc,
		0,
		0,
		hInstance,
		0,
		LoadCursor(0, IDC_ARROW),
		0,
		0,
		szClassName
	};
	RegisterClass(&wndclass);
	HWND hWnd = CreateWindow(
		szClassName,
		TEXT("Color Clock"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		0,
		CW_USEDEFAULT,
		0,
		0,
		0,
		hInstance,
		0
		);
	ShowWindow(hWnd, SW_SHOWDEFAULT);
	UpdateWindow(hWnd);
	while (GetMessage(&msg, 0, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
    このエントリーをはてなブックマークに追加 mixiチェック

無駄にかっこいいコマンドプロンプト

前回の記事で、ウィンドウの背景を半透明ブラシにする方法が分かったが、この方法をコマンドプロンプトに適用してみたところ割と綺麗にいったので紹介する。

以下のプログラムは、コマンドプロンプトを起動して例の "SetWindowCompositionAttribute" を設定することにより、コマンドプロンプトの背景を半透明ボカシにするコード

白っぽい背景の場合は、文字が見にくくなるが、思った以上に綺麗に動作している。

プロジェクトのダウンロード

#include<windows.h>

BOOL bSetWindowBlur;

void SetWindowBlur(HWND hWnd)
{
	const HINSTANCE hModule = LoadLibrary(TEXT("user32.dll"));
	if (hModule)
	{
		struct ACCENTPOLICY
		{
			int nAccentState;
			int nFlags;
			int nColor;
			int nAnimationId;
		};
		struct WINCOMPATTRDATA
		{
			int nAttribute;
			PVOID pData;
			ULONG ulDataSize;
		};
		typedef BOOL(WINAPI*pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA*);
		const pSetWindowCompositionAttribute SetWindowCompositionAttribute = (pSetWindowCompositionAttribute)GetProcAddress(hModule, "SetWindowCompositionAttribute");
		if (SetWindowCompositionAttribute)
		{
			ACCENTPOLICY policy = { 3, 0, 0, 0 };
			WINCOMPATTRDATA data = { 19, &policy, sizeof(ACCENTPOLICY) };
			SetWindowCompositionAttribute(hWnd, &data);
		}
		FreeLibrary(hModule);
	}
}

BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
	DWORD dwProcessId;
	GetWindowThreadProcessId(hWnd, &dwProcessId);
	if (dwProcessId == lParam)
	{
		SetWindowBlur(hWnd);
		bSetWindowBlur = TRUE;
		return FALSE;
	}
	return TRUE;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR pCmdLine, int nCmdShow)
{
	PROCESS_INFORMATION pInfo = { 0 };
	STARTUPINFO sInfo = { 0 };

	sInfo.cb = sizeof(STARTUPINFO);
	sInfo.dwFlags = STARTF_USESHOWWINDOW;
	sInfo.wShowWindow = nCmdShow;

	TCHAR szCommandLine[MAX_PATH];
	if (GetEnvironmentVariable(TEXT("ComSpec"), szCommandLine, MAX_PATH) && CreateProcess(0, szCommandLine, 0, 0, 0, 0, 0, 0, &sInfo, &pInfo))
	{
		CloseHandle(pInfo.hThread);
		WaitForInputIdle(pInfo.hProcess, INFINITE);
		CloseHandle(pInfo.hProcess);
		while (!bSetWindowBlur)
		{
			EnumWindows(EnumWindowsProc, (LPARAM)pInfo.dwProcessId);
		}
	}
	return 0;
}
    このエントリーをはてなブックマークに追加 mixiチェック

preview

Windows 10でスタートメニューやネットワーク選択画面などで半透明ボカシのかかったウィンドウが使われているが、現在公式に公開されているAPIはないようだ。

Webで調べてみると少し裏ワザチックだが、user32.dll に "SetWindowCompositionAttribute" という関数が含まれていて GetProcAddress でこの関数をロードして使うと、ウィンドウを半透明ボカシにすることが可能ということが分かった。

参考にしたサイト

背景色などを設定する方法がまだわからないので、明るい背景になるときはウィンドウがとても見えずらくなる。このあたりは引数など、さらなる研究が必要だ。

プロジェクトのダウンロード

#include <windows.h>

TCHAR szClassName[] = TEXT("Window");

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			const HDC hdc = BeginPaint(hWnd, &ps);
			SetTextColor(hdc, RGB(255, 255, 255));
			SetBkMode(hdc, TRANSPARENT);
			TextOut(hdc, 10, 10, TEXT("Hello, world!"), 13);
			EndPaint(hWnd, &ps);
		}
		break;
	case WM_NCHITTEST:
		wParam = DefWindowProc(hWnd, msg, wParam, lParam);
		if (wParam == HTCLIENT)
			return HTCAPTION;
		else
			return wParam;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, msg, wParam, lParam);
	}
	return 0;
}

void SetWindowBlur(HWND hWnd)
{
	const HINSTANCE hModule = LoadLibrary(TEXT("user32.dll"));
	if (hModule)
	{
		struct ACCENTPOLICY
		{
			int nAccentState;
			int nFlags;
			int nColor;
			int nAnimationId;
		};
		struct WINCOMPATTRDATA
		{
			int nAttribute;
			PVOID pData;
			ULONG ulDataSize;
		};
		typedef BOOL(WINAPI*pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA*);
		const pSetWindowCompositionAttribute SetWindowCompositionAttribute = (pSetWindowCompositionAttribute)GetProcAddress(hModule, "SetWindowCompositionAttribute");
		if (SetWindowCompositionAttribute)
		{
			ACCENTPOLICY policy = { 3, 0, 0, 0 };
			WINCOMPATTRDATA data = { 19, &policy, sizeof(ACCENTPOLICY) };
			SetWindowCompositionAttribute(hWnd, &data);
		}
		FreeLibrary(hModule);
	}
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR pCmdLine, int nCmdShow)
{
	MSG msg;
	WNDCLASS wndclass = {
		0,
		WndProc,
		0,
		0,
		hInstance,
		0,
		LoadCursor(0, IDC_ARROW),
		(HBRUSH)GetStockObject(BLACK_BRUSH),
		0,
		szClassName
	};
	RegisterClass(&wndclass);
	HWND hWnd = CreateWindow(
		szClassName,
		TEXT("Window"),
		WS_POPUPWINDOW,
		0,
		0,
		500,
		500,
		0,
		0,
		hInstance,
		0
		);
	SetWindowBlur(hWnd);
	ShowWindow(hWnd, SW_SHOWDEFAULT);
	UpdateWindow(hWnd);
	while (GetMessage(&msg, 0, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
    このエントリーをはてなブックマークに追加 mixiチェック

このページのトップヘ