WisdomSoft - for your serial experiences.

ウィンドウ削除

登録したウィンドウクラスや、生成したウィンドウはプログラムから明示的に削除できます。

ウィンドウを破棄して画面から消す

通常、アプリケーションの閉じるボタンを押せば、後述する DefWindowProc() 関数の作用で自動的にウィンドウが閉じられます。明示的に自分のコードからウィンドウを削除することもできます。

アプリケーションによって明示的に生成したウィンドウを破棄することもできます。ただし「ウィンドウ生成」で解説したコードのように、アプリケーションが終了すれば自動的に有効なウィンドウは破棄され、登録されているクラスも解除される仕組みになっています。そのため、ウィンドウの破棄やウィンドウクラスの解除を明示的に記述するのは、アプリケーションの実行中に何らかの理由から破棄したい場合です。

CreateWindow() 関数や CreateWindowEx() 関数で生成した有効なウィンドウを削除するには DestroyWindow() 関数を使います。

DestroyWindow() 関数
BOOL DestroyWindow(HWND hWnd);

関数が成功すれば 0 以外の値が、失敗すれば 0 が返ります。ウィンドウが何らかの子ウィンドウを持つ場合は、子ウィンドウも含めて、子ウィンドウから順に破棄します。そのほか、メニューなどのウィンドウに関連したあらゆるリソースが破棄されます。

コード1
#include <windows.h>
#define WINDOWS_CLASS_NAME TEXT("WisdomSoft.Sample.Window")

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	HWND window;
	WNDCLASSEX wcx;

	wcx.cbSize = sizeof(WNDCLASSEX);
	wcx.style = CS_HREDRAW | CS_VREDRAW;
	wcx.lpfnWndProc = DefWindowProc;
	wcx.cbClsExtra = 0;
	wcx.cbWndExtra = 0;
	wcx.hInstance = hInstance;
	wcx.hIcon =  NULL;
	wcx.hCursor = NULL;
	wcx.hbrBackground = (HBRUSH)COLOR_BACKGROUND + 1;
	wcx.lpszMenuName = NULL;
	wcx.lpszClassName = WINDOWS_CLASS_NAME;
	wcx.hIconSm = NULL;

	if (!RegisterClassEx(&wcx)) 
	{
		OutputDebugString(TEXT("Error: ウィンドウクラスの登録ができません。\n"));
		return 0;
	}

	window = CreateWindowEx(
		WS_EX_LEFT, WINDOWS_CLASS_NAME, TEXT("Window Title"),
		WS_OVERLAPPEDWINDOW | WS_VISIBLE,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInstance ,NULL
	);
	if (!window)
	{
		OutputDebugString(TEXT("Error: ウィンドウが作成できません。\n"));
		return 0;
	}

	MessageBox(window , TEXT("OKボタンを押すと終了します") , TEXT("情報") , MB_OK);

	if (DestroyWindow(window))
		MessageBox(NULL , TEXT("ウィンドウを削除しました") , TEXT("情報") , MB_OK);

	return 0;
}
実行結果
コード1 実行結果

コード1は、アプリケーションを終了させる直前にウィンドウを明示的に破棄します。2回目のメッセージボックスが表示されたとき、背景のウィンドウが DestroyWindow() 関数の働きによって閉じられることが確認できます。

DestroyWindow() 関数は、完全にウィンドウを削除してしまいます。単にウィンドウが非表示になるのではありません。メモリからウィンドウの情報が解放されます。

ウィンドウクラスの登録解除

RegisterClass() 関数で登録したウィンドウクラスは UnregisterClass() 関数で登録を解除できます。使用しなくなったウィンドウクラスをシステムから削除するために使います。

UnregisterClass() 関数
BOOL UnregisterClass(LPCTSTR lpClassName, HINSTANCE hInstance);

lpClassName パラメータにはウィンドウクラスの名前を表す文字列、または RegisterClass() 関数が返したアトムを指定できます。ここに指定したウィンドウクラスが解除されます。

hInstance パラメータには、クラスを作成したインスタンスハンドルを指定します。ここに指定するのは WinMain() 関数から取得したインスタンスハンドルではなく、WNDCLASS 構造体のメンバに指定した、ウィンドウクラスの登録に使用されたインスタンスハンドルです。

UnregisterClass() でウィンドウクラスを解除するには、そのウィンドウクラスに属するウィンドウをすべて破棄していなければなりません。関数が成功すれば 0 以外の値が返り、失敗すれば 0 が返ります。

コード2
#include <windows.h>
#define WINDOWS_CLASS_NAME TEXT("WisdomSoft.Sample.Window")

void InitApplicationWindow(HINSTANCE application)
{
	HWND window;

	window = CreateWindowEx(
		WS_EX_LEFT, WINDOWS_CLASS_NAME, TEXT("Window Title"),
		WS_OVERLAPPEDWINDOW | WS_VISIBLE,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, application ,NULL
	);
	if (!window)
	{
		MessageBox(NULL , TEXT("ウィンドウを作成できません") , NULL , MB_ICONERROR);
		return;
	}

	MessageBox(NULL , TEXT("OKを押すとウィンドウを削除します") , TEXT("情報") , MB_OK);
	DestroyWindow(window);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	HWND window;
	WNDCLASSEX wcx;

	wcx.cbSize = sizeof(WNDCLASSEX);
	wcx.style = CS_HREDRAW | CS_VREDRAW;
	wcx.lpfnWndProc = DefWindowProc;
	wcx.cbClsExtra = 0;
	wcx.cbWndExtra = 0;
	wcx.hInstance = hInstance;
	wcx.hIcon =  NULL;
	wcx.hCursor = NULL;
	wcx.hbrBackground = (HBRUSH)COLOR_BACKGROUND + 1;
	wcx.lpszMenuName = NULL;
	wcx.lpszClassName = WINDOWS_CLASS_NAME;
	wcx.hIconSm = NULL;

	if (!RegisterClassEx(&wcx)) 
	{
		OutputDebugString(TEXT("Error: ウィンドウクラスの登録ができません。\n"));
		return 0;
	}

	InitApplicationWindow(hInstance); //OK

	if (UnregisterClass(wcx.lpszClassName, wcx.hInstance))
		MessageBox(NULL , TEXT("ウィンドウクラスの登録を解除しました") , TEXT("情報") , MB_OK);

	InitApplicationWindow(hInstance); //エラー

	return 0;
}
実行結果
コード2 実行結果

コード2は InitApplicationWindow() 関数でウィンドウを生成します。WinMain() 関数から 2 回 InitApplicationWindow() 関数を呼び出していますが、2 回目の呼び出しの前に、意図的にウィンドウクラスを削除しています。その結果、2 回目の InitApplicationWindow() 関数では CreateWindowEx() 関数がウィンドウクラスを発見できずにエラーとなります。この結果から、正しくウィンドウクラスが解除されていることが確認できます。

ウィンドウの削除やウィンドウクラスの解除処理は、アプリケーションが終了した後 Windows システムが自動的に行ってくれるため必須ではありません。アプリケーションが処理を行っている中でウィンドウクラスを削除したい場合などに使える方法です。通常のアプリケーションには不要ですが、動的言語の仮想マシンなど、開発ツール的な分野の開発で応用できるでしょう。