「ファイルを開く」コモンダイアログ

前回のプログラムは、かなりWindowsプログラムらしくなったのですが、ただ、どうも使いにくいようです。 ひとつには、ファイル名をいちいち入力しないといけないのがその原因です。では、 ファイル選択ダイアログを出すようにしましょう。 ついでにファイルが存在しない時やバージョン情報などのメッセージボックスを出します。 この時ちゃんと親ウインドウを指定しないと困ったことになります。(スタックオーバーフロー)

コモンダイアログとは、よく使うダイアログをWindowsシステムが供給するものです。 ファイルオープンダイアログの他、印刷ダイアログ、検索/置換ダイアログなどがあります。 これを使うには、まずソースに#include <commdlg.h>を追加します。リンク時には、 16ビットならcommdlg.lib、32ビットならcomdlg32.libを追加指定する必要があります。

では実際にやってみましょう。まず、メインのダイアログに「参照」ボタンを追加します。

    PUSHBUTTON "参照",  IDBROWSE, 96, 3, 40, 14
ヘッダファイルには、以下の記述を追加。
#define IDBROWSE 105
そして、C言語ソースに、以下の記述を追加します。 まず、easyplay関数のローカル変数に、以下を追加。
	static OPENFILENAME ofn;
	int flag;
	char achFileTitle[256];
それから、switch((WORD)wParam) { の部分に、以下を追加。
	case IDBROWSE:
		memset(&ofn, 0, sizeof(OPENFILENAME));
		ofn.lStructSize = sizeof(OPENFILENAME);
		ofn.hwndOwner = hDlg;
		ofn.lpstrFilter = "サウンド(*.WAV)\0*.WAV\0全ファイル(*.*)\0*.*\0";
		ofn.lpstrCustomFilter = NULL;
		ofn.nFilterIndex = 1;
		buf[0] = 0;
		ofn.lpstrFile = (LPSTR)buf;
		ofn.nMaxFile = sizeof(buf);
		ofn.lpstrFileTitle = (LPSTR)achFileTitle;
		ofn.nMaxFileTitle = sizeof(achFileTitle);
		ofn.lpstrInitialDir = NULL;
		ofn.lpstrTitle = "再生用にファイルを開く";
		ofn.lpstrDefExt = NULL;
		ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
		flag=GetOpenFileName((LPOPENFILENAME)&ofn);
		if (flag)
			SetDlgItemText(hDlg, IDEDIT, buf);
		break;
以上で、ファイルオープンのコモンダイアログの追加は終わりです。構造体メンバに値を設定し、 GetOpenFileName()を呼び出すだけです。このAPIの戻り値は、OKの時TRUEに、キャンセルの時 FALSEになるので、それを見てファイル名をエディットコントロールにコピーしています。簡単ですね。

その他の細かい改良

まずは、再生中にもボタンが押せるように見えてしまう(実際には押せない)のはおかしいので、 コントロールの有効/無効を切り換えます。これには、EnableWindow()というAPIを使います。 ついでに、カーソルを砂時計にします。

あと、よりWindowsプログラムらしくするため、バージョン情報ダイアログを追加しましょう。 といっても、別途ダイアログをデザインするのは面倒なので、MessageBox()で済ませます。 まず、システムメニューに項目を追加します。それから、それが選択された時の動作をプログラムします。 システムメニューに追加した項目は、選択されるとWM_SYSCOMMANDを送ってきます。
注意!WM_SYSCOMMANDで、自分で追加した以外のメッセージにTRUEを返す (メッセージを握りつぶす)のは禁じ手です。もしそれをやると、タイトルバーをマウスでドラッグして 移動することもできなくなりますし、「×」ボタンも効かなくなります。

あと、ファイル名が未入力だった場合や、ファイルが存在しなかった場合、Waveファイルではなかった 場合など、エラーメッセージを出すようにします。SndPlaySound()の戻り値で、再生が成功したかどうか 分かります。

修正後の全ソース

ついでに最小化をサポートしようと思って、ダイアログのスタイルにWS_MINIMIZEBOX を追加したら、システムメニューには最大化なども追加されてしまった……どうしよう?

コモンダイアログの注意事項

Windows 2000では、OPENFILENAME構造体のメンバが増えました。また、マイクロソフトが提供している 最新のSDKのヘッダファイルでは、何も指定しないときにはWindows 2000用のプログラムを作成するように なっています。このため、Borland C++ 5.5など最新のコンパイラで何も考えずにファイルオープンの コモンダイアログを使ったソースをコンパイルすると、Windows 95や98で動かないものができてしまいます。 回避方法は二つあります。

その1

増えたメンハが特に必要ない場合、
#define WINVER 0x400
#define _WIN32_WINNT 0
#define _WIN32_IE 0
をソース先頭に追加すれば良いのですが、毎回ソースを修正するのは不便なので、コンパイラの オプションで設定すると良いでしょう。Borland C++ 5.5の場合
-DWINVER=0x400
-D_WIN32_WINNT=0
-D_WIN32_IE=0
をBCC32.CFGに追加します。

その2

増えたメンバをWindows2000では使いたい場合、実行時にバージョンチェック(GetVersion()等を使用) して,以下のように書きます。ただしこのソースは古いコンパイラではコンパイル不能になります。
if (Windows2000以降)
    ofn.lStructSize = sizeof(OPENFILENAME);
else
    ofn.IStructSize = OPENFILENAME_SIZE_VERSION_400;

ファイル名を受け取る、その他の方法

コマンドライン引数を使う方法や、 ドラッグ&ドロップを使う方法があります。

前のページ

次のページ

一つ上のページに戻る