ダイアログ

■概要

ダイアログとはGUI(Graphical User Interface)で、
ユーザーに入力を求めたり、通知を行うために表示するウィンドウのことです。
Windowsのプログラムでよく利用されるメッセージボックスもダイアログの一種です。

■自作ダイアログの基本

ダイアログもリソースとして扱われていますので、
リソースファイルを用意することで自作のダイアログの作成が可能です。
ただ、ダイアログは「ボタン」や「テキスト」など、複数のアイテムから
構成されているので、ファイル作成はResEditなどのツールを使用した方が
効率はいいと思います。

●サンプル用ダイアログリソース
	今回使用するダイアログのリソースとヘッダファイルを
	以下のリンクからダウンロードして下さい。

	ダイアログリソース

	ヘッダファイル

●自作ダイアログの使用方法
	・サンプルコード
		#define WIN32_LEAN_AND_MEAN

		#include <Windows.h>
		#include <winsock.h>
		#include "resource.h"

		#pragma comment(lib, "Ws2_32.lib")

		// ② ダイアログ用のウィンドウプロシージャの作成
		LRESULT CALLBACK ServerProc(HWND, UINT, WPARAM, LPARAM);

		// ② ダイアログ用のウィンドウプロシージャの作成
		LRESULT CALLBACK ServerProc(HWND dialog_handle, 
						UINT message, 
						WPARAM wp, 
						LPARAM lp)
		{
			HWND send_button;

			switch (message)
			{
			// ④.ダイアログの初期化
			case WM_INITDIALOG:
				send_button = GetDlgItem(dialog_handle, IDC_SENDBTN);
				EnableWindow(send_button, FALSE);
				break;
			// ⑤.ダイアログ終了
			case WM_CLOSE:
				// ダイアログ終了
				EndDialog(dialog_handle, WM_CLOSE);
				break;
			default:
				return false;
			}

			return true;
		}

		int WINAPI WinMain(HINSTANCE instance_handle,
					 HINSTANCE prev_instance_handle, 
					LPSTR cmd_line, 
					int cmd_show)
		{
			// ③ ダイアログ作成
			DialogBox(instance_handle, 
					TEXT("SERVER_DLG"), 
					NULL, 
					(DLGPROC)ServerProc);

			return 0;
		}

	・手順
		①.プロジェクトにリソースファイルとresource.hを追加する
			自作ダイアログを使用するプロジェクトに
			ダイアログの情報をコーディングしているリソースファイルと
			そこで使用しているリソースIDを定義しているresource.hを追加します。

		②.ダイアログウィンドウ用のプロシージャを作成する
			ダイアログウィンドウのボタンをクリックされた場合などの
			メッセージイベントを処理するためのプロシージャを作成します。

			・ダイアログプロシージャの基本形
				LRESULT CALLBACK 関数名(HWND, UINT, WPARAM, LPARAM)

				戻り値:
					LRESULT:
						基本的に自分でメッセージを処理した場合はtrue、
						何もしなかったらfalseを返す

				CALLBACK:
					WINAPIと同様の呼び出し規約

				引数:
					HWND:
						ウィンドウハンドル

					UINT:
						メッセージ

					WPARAM、LPARAM:
						メッセージに対する付加情報
						メッセージの内容で情報は異なる

		③.DialogBox関数でダイアログを作成する
			自作ダイアログの作成はDialogBox関数を使用します。

			・DialogBox関数
				int DialogBox(HINSTANCE, LPCTSTR, HWND, DLGPROC)

				関数名:
					DialogBox
				戻り値:
					成功:
						EndDialogの第二引数の値
					失敗:
						0 or -1
				引数:
					HINSTANCE 
						アプリのインスタンスハンドル
					LPCSTR
						ダイアログの名前
					HWND
						親のウィンドウハンドル
					DLGPROC
						ダイアログ用プロシージャ

				内容:
					Dialogを作成する
					使用するダイアログは第二引数のダイアログの名前で決める
					作成に成功した場合、ダイアログが閉じられるまで、
					コード上の処理が進まなくなるので、注意が必要

		④.ダイアログの初期化
			ダイアログが作成された直後、プロシージャに「WM_INITDIALOG」という
			メッセージが送信されるので、この時にダイアログの初期化処理を行いないます。
			処理の内容はダイアログごとに違うので、必ずやることはありませんが、
			何もしなかった場合は「false」を返すようにして下さい。

			・何もしなかった場合:
				switch (message)
				{
				// ダイアログの初期化
				case WM_INITDIALOG:
					return false;
					break;
				}

			・何かしらの処理を行った場合:
				HWND send_button;
			
				switch (message)
				{
				// ダイアログの初期化
				case WM_INITDIALOG:
					// 送信ボタン取得後、非アクティブ設定
					send_button = GetDlgItem(dialog_handle, IDC_SENDBTN);
					EnableWindow(send_button, FALSE);
					return true;
					break;
				}

		⑤.ダイアログの終了
			ダイアログの終了はEndDialog関数を使用します。
			ですが、ダイアログの終了タイミングはダイアログによって異なりますので、
			ここでは「×」ボタンを押した際の終了の流れで説明したいと思います。

			・EndDialog関数
				BOOL EndDiaDlog(HWND, INT_PTR)

				関数名:
					EndDialog
				戻り値:
					成功:0
					失敗:非0
				引数:
					HWND:このダイアログのハンドル
					INT_PTR:アプリケーションへ返したい値(intの値で可)
				内容:
					引数で指定されたハンドルのダイアログを終了する
					その際、DialogBox関数への戻り値の設定として
					第二引数に値を設定する

			・具体例:
				switch (message)
				{
				// 「×」ボタンクリック
				case WM_CLOSE:
					// ダイアログを閉じる
					EndDialog(dialog_handle, WM_CLOSE);
					return true;
					break;
				}

■自作ダイアログの応用

上記は自作ダイアログの作成と終了のみ記述していますので、
ここからは自作ダイアログで設定しているボタンやテキストの情報の取得方法や
プロシージャで通知されるイベントメッセージについて記述していきたいと思います。
	
●イベントメッセージ
	ダイアログ内のボタンをクリックした際のイベントメッセージは
	「WM_COMMAND」としてプロシージャに通知されます。
	どのボタンが押されたかについての情報は「WPARAM」に格納されており、
	LOWORDマクロを使用することで取得できます。
	このLOWORDで取得できる情報は「resource.h」で宣言しているIDです。

	例:
		switch (message)
		{
		// ダイアログの初期化
		case WM_INITDIALOG:
			return FALSE;
			break;
		// 「×」ボタンクリック
		case WM_CLOSE:
			// ダイアログ終了
			EndDialog(dialog_handle, WM_CLOSE);
			break;
		// イベントメッセージ
		case WM_COMMAND:
			switch (LOWORD(wp))
			{
			// 送信ボタン
			case IDC_SENDBTN:
				MessageBox(dialog_handle, 
						TEXT("送信"), 
						TEXT("送信ボタンクリック"), 
						MB_OK);
				break;
			// 開始ボタン
			case IDC_STARTBTN:
				MessageBox(dialog_handle, 
						TEXT("開始"), 
						TEXT("開始ボタンクリック"), 
						MB_OK);
				break;
			// 終了ボタン
			case IDC_ENDBTN:
				MessageBox(dialog_handle, 
						TEXT("終了"), 
						TEXT("終了ボタンクリック"), 
						MB_OK);
				break;
			}
			break;
		default:
			return false;
		}

●ダイアログ情報の取得
	エディットテキストに設定している情報は「GetDlgItem~」関数で取得することができます。

	・GetDlgItem
		HWND GetDlgItem(HWND, int)

		関数名:
			GetDlgItem
		
		戻り値:
			成功:ハンドル
			失敗:NULL
		
		引数:
			HWND:
				アイテムを取得するダイアログボックスのハンドル
			
			int:
				アイテムのID
			
		内容:
			指定したダイアログボックスからアイテムを取得する
			そのアイテムをアクティブ、非アクティブ化する場合などに使用する

		具体例:
			// 送信ボタンのハンドルの取得
			HWND send_button = GetDlgItem(dialog_handle, IDC_SENDBTN);

	・GetDlgItemInt
		UINT GetDlgItemInt(HWND, int, BOOL *, BOOL);

		戻り値:
			成功:第三引数にTRUEが設定され、
			      アイテムに設定されている数値が取得される
			失敗:第三引数にFALSEが設定され、
			   0が返される

		引数:
			HWND:
				取得したいアイテムのあるダイアログボックスのハンドル

			int:
				取得したい数値の入った文字列のあるアイテムのID

			BOOL *:
				成功か失敗を判断するBOOL値

			BOOL:
				符号有りかなしか

				TRUE:
					符号有り
					※戻り値をキャストする必要有り
				FALSE:
					符号無し
		
		内容:
			指定したダイアログのアイテムの情報を数値として取得する

		具体例:
			// ポート番号入力項目に設定されている数値を取得
			BOOL is_get_item = false;
			int num = (int)GetDlgItmInt(
						dialog_handle,
						IDC_PORT,
						&is_get_item,
						true);

	・GetDlgItemText
		UINT GetDlgItemText(HWND, int, LPTSTR, int);

		関数名:
			GetDlgItemText

		戻り値:
			成功:文字列の長さ
			失敗:0

		引数:
			HWND:
				取得したいアイテムのあるダイアログボックスのハンドル

			int:
				文字列を取得したいアイテムのあるID

			LPTSTR:
				取得する文字列のバッファ(TCHAR単位)

			int:
				文字列の長さ

		内容:
			指定したダイアログのアイテムの情報を文字列として取得する

		具体例:
			// 送信文をエディットテキストから取得
			TCHAR buff[1024];
			UINT str_len = GetDlgItmInt(
						dialog_handle,
						IDC_SEND,
						buff,
						1024);

●サンプルコード
	#define WIN32_LEAN_AND_MEAN

	#include <Windows.h>
	#include <winsock.h>
	#include "resource.h"
	#include <stdio.h>

	#pragma comment(lib, "Ws2_32.lib")
	LRESULT CALLBACK ServerProc(HWND, UINT, WPARAM, LPARAM);

	int WINAPI WinMain(HINSTANCE instance_handle, 
				HINSTANCE prev_instance_handle, 
				LPSTR cmd_line, 
				int cmd_show)
	{
		WSADATA wsadata;

		DialogBox(instance_handle, TEXT("SERVER_DLG"), NULL, (DLGPROC)ServerProc);

		return 0;
	}

	LRESULT CALLBACK ServerProc(HWND dialog_handle, UINT message, WPARAM wp, LPARAM lp)
	{
		HWND end_button;
		int port_no;
		TCHAR buff[1024];
		BOOL is_success = false;

		switch (message)
		{
		// ダイアログの初期化
		case WM_INITDIALOG:
			return FALSE;
			break;
		// 「×」ボタンクリック
		case WM_CLOSE:
			// ダイアログ終了
			EndDialog(dialog_handle, WM_CLOSE);
			break;
		// イベントメッセージ
		case WM_COMMAND:
			switch (LOWORD(wp))
			{
			case IDC_SENDBTN:
				// 送信文を取得して表示
				GetDlgItemText(dialog_handle, 
						IDC_SEND, 
						buff, 
						1024);
				MessageBox(dialog_handle, buff, TEXT("送信"), MB_OK);
				break;
			case IDC_STARTBTN:
				// ポート番号を取得して表示
				port_no = GetDlgItemInt(dialog_handle, 
							IDC_PORT, 
							&is_success, 
							true);
				wsprintf(buff, TEXT("port_no = %d"), port_no);
				MessageBox(dialog_handle, 
						buff, 
						TEXT("開始"), 
						MB_OK);
				break;
			case IDC_ENDBTN:
				// アイテムを取得して非アクティブ設定
				end_button = GetDlgItem(dialog_handle, IDC_ENDBTN);
				EnableWindow(end_button, false);
				break;
			}
			break;
		default:
			return false;
		}

		return true;
	}