CUIからGUIへ(2)

さて、ここまでで作ったプログラムだが、Windowsで育った世代にはCUIがしょぼすぎて不満が多いだろう。プログラムをウィンドウ化して、ファイルの指定にしてもコマンドからではなく、ファイルオープンダイアログなどを使いたい。

そこで、このプログラムをダイアログベースに書き直すことにする。

なお、ここではVC6.0をベースに話を進めていく。

ダイアログを表示する

これは非常に簡単に出来る。新規プロジェクトの作成でMFCダイアログベースを選んで、ビルドすればそれだけでそれっぽいダイアログが表示される。

この状態では"OK"を押しても"キャンセル"を押してもプログラムが終了してしまうので、すこし書き換えてみよう。

ダイアログの編集画面でOKボタンをダブルクリックすると

void CD6Dlg::OnOK() 
{
// TODO: この位置にその他の検証用のコードを追加してください
	CDialog::OnOK();
}

といったコードが生成される。この関数が"OK"ボタンが押されたときに呼ばれる関数だ。
OnOK();をコメントアウトして実行すると"OK"を押しても終了しなくなる。


ごめ、こっから下要らないですw

Windows風ファイル操作

MFCをつかってGUIプログラミングを行う場合、ファイル操作もC言語標準のfopenなどではなく、WindowsAPIを使ったほうが自然であり、なにより資源を利用しやすい。

なので、一旦fopenなどは忘却の彼方に追いやり、http://wisdom.sakura.ne.jp/system/winapi/win32/win111.html
ここを熟読してもらいたい。

熟読し終わったら、実際にファイルを開いてみよう。先のダイアログのOnBnClickedOk()を以下のように書き換える。

void CD6Dlg::OnOK() 
{
	HANDLE hSrcFile;

	hSrcFile = CreateFile(
		"aaa.txt" , GENERIC_READ , 0 , NULL ,
		OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL
	);
	if (hSrcFile == INVALID_HANDLE_VALUE) {
		MessageBox(
			TEXT("aaa.txtファイルがありません。") ,
			TEXT("エラー") , MB_OK
		);
		return;
	}

	MessageBox(
		TEXT("aaa.txtを開きました。") ,
		TEXT("報告") , MB_OK
	);

	CloseHandle(hSrcFile);
	//CDialog::OnOK();
}

これでOKボタンを押すとaaa.txtファイルを開いて閉じるプログラムが完成する。開いて閉じるだけなので当然何もしないが、ファイルの存在のチェックができる。

ファイル読み書き

ファイルのオープンが出来たので、内容をほかのファイルに出力するプログラムを作成する。

まずはこれを熟読。
http://wisdom.sakura.ne.jp/system/winapi/win32/win113.html

なにやら知らない型やら関数やらがたくさん出てきてつらいかもしれないが、今回使うのはこれだけ

void CD6Dlg::OnOK() 
{
	HANDLE hSrcFile;

	// 元ファイルの読み込み
	hSrcFile = CreateFile(
		"aaa.txt" , GENERIC_READ , 0 , NULL ,
		OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL
	);
	if (hSrcFile == INVALID_HANDLE_VALUE) {
		MessageBox(
			TEXT("aaa.txtファイルがありません。") ,
			TEXT("エラー") , MB_OK
		);
		return;
	}
	// +1は\0の分の確保
	LPSTR strFile = 
		(LPSTR)malloc(GetFileSize(hSrcFile , NULL) + 1);

	DWORD dwSize;
	ReadFile(hSrcFile , strFile , GetFileSize(hSrcFile , NULL),
	 &dwSize , NULL);
	strFile[dwSize] = '\0';


	// 対象ファイルの出力
	HANDLE hDestFile = CreateFile(
		"out.txt", GENERIC_WRITE , 0 , NULL ,
		CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL
	);
	WriteFile(hDestFile , strFile , lstrlen(strFile) ,
	 &dwSize , NULL);


	CloseHandle(hSrcFile);
	CloseHandle(hDestFile);
	CDialog::OnOK();
}

ファイル名がプログラムに埋め込んであるのがアレだが、とりあえずこれで同じ内容のファイルをコピーすることが出来た。