ファイルダイアログ

メニューとファイルダイアログ

応用編第2日目 では、メニューの取扱型を学びました。ウィンドウアプリのメニューでは、様々な処理を行うことができますが、その中でもよく用いられるのが、データの保存・読み出しといった、ファイル操作です。その際、ファイルを開いたり、保存したりするのに用いられるのが、ファイルダイアログです。

サンプルプログラム

以下のサンプルは応用編第2日目のサンプルと同じリソースに、新たにメニュー項目「開く(O)」を加え、ファイルダイアログが出現するようにプログラムを変更したものです。

win32exproj3-1:WinMain.cpp
// ************************************
// Ex メニュー・ポップアップメニュー
// ************************************
//必要なヘッダーファイルのインクルード
#define STRICT

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>

//	リソースの読み込み
#include "resource.h"

// シンボル定義及びマクロ
#define WINDOW_WIDTH    800
#define WINDOW_HEIGHT   600

//	インスタンス(グローバル変数)
HINSTANCE hInst;

//	ウィンドウプロシージャのコールバック関数
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nCmdShow)
{
	static TCHAR szWindowClass[] = _T("Sample03");
	static TCHAR szTitle[] = _T("ファイルダイアログのサンプル");

	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
	wcex.lpszClassName = szWindowClass;
	wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

	if (!RegisterClassEx(&wcex))
	{
		MessageBox(NULL,
			_T("RegisterClassExの処理に失敗しました"),
			_T("Sample03"),
			NULL);

		return 1;
	}

	hInst = hInstance; // グローバル変数に値を入れる

	// The parameters to CreateWindow explained:
	// szWindowClass				: アプリケーションの名前
	// szTitle						: タイトルバーに現れる文字列
	// WS_OVERLAPPEDWINDOW			: 生成するウィンドウのタイプ
	// CW_USEDEFAULT, CW_USEDEFAULT	: 最初に置くポジション (x, y)
	// WINDOW_WIDTH, WINDOW_HEIGHT	: 最初のサイズ (幅, 高さ)
	// NULL							: このウィンドウの親ウィンドウのハンドル
	// NULL							: メニューバー(このサンプルでは使用せず)
	// hInstance					: WinMain関数の最初のパラメータ
	// NULL							: WM_CREATE情報(このアプリケーションでは使用せず)
	HWND hWnd = CreateWindow(
		szWindowClass,
		szTitle,
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT,
		WINDOW_WIDTH, WINDOW_HEIGHT,
		NULL,
		NULL,
		hInstance,
		NULL
		);
	//	ウィンドウが生成できなかった場合
	if (!hWnd)
	{
		MessageBox(NULL,
			_T("ウィンドウ生成に失敗しました!"),
			_T("Sample03"),
			NULL);
		return 1;
	}

	// ウィンドウの表示に必要なパラメータ:
	// hWnd		: CreateWindowの戻り値
	// nCmdShow	: WinMainの引数の4番目
	ShowWindow(hWnd,
		nCmdShow);
	UpdateWindow(hWnd);

	// メインのメッセージループ:
	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return (int)msg.wParam;
}

//	ウィンドウプロシージャ(メッセージに対するコールバック関数)
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    //ポイント構造体
    POINT    pt;
    //ファイルオープン関係
    OPENFILENAME oFileName;
    TCHAR szFileName[MAX_PATH]=_T("");
    TCHAR szFileTitle[64]=_T("");
    TCHAR szBuffer[MAX_PATH]=_T("");
	switch (message)
	{
    //キーを押した
    case WM_KEYDOWN:
        switch(wParam)
        {
        case VK_ESCAPE:
            //終了メッセージを発生させる
            PostMessage(hWnd, WM_CLOSE, 0, 0);
            break;
        }
        break;
    //ウインドウが生成されたときに1度だけ通過
    case WM_CREATE:
        break;
    //マウス右クリック
    case WM_RBUTTONDOWN:
        pt.x = LOWORD(lParam);
        pt.y = HIWORD(lParam);
        //クライアント座標をスクリーン座標へ変換
        ClientToScreen( hWnd, &pt);
        //ポップアップメニューを表示
        TrackPopupMenu( GetSubMenu( GetMenu( hWnd ), 0), TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL);
        break;
    case WM_COMMAND:
        switch( LOWORD(wParam) )
        {
        case ID_40001:
            //バージョン(A)
            MessageBox(hWnd, _T("メニューの実装Ver1.0"), _T("バージョン情報"), MB_OK);
            break;
        case ID_40002:
            //終了(X)
            PostMessage(hWnd, WM_CLOSE, 0, 0);
            break;
		case ID_40003:
            //開く(O)
            ZeroMemory( &oFileName, sizeof( OPENFILENAME ) );
            oFileName.lStructSize     = sizeof( OPENFILENAME );
            oFileName.hwndOwner       = hWnd;
            oFileName.lpstrFilter     = _T("DOC Files\0*.doc;\0All Files(*.*)\0*.*\0\0");
            oFileName.nFilterIndex    = 1;
            oFileName.lpstrFile       = szFileName;
            oFileName.nMaxFile        = MAX_PATH;
            oFileName.Flags           = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
            oFileName.lpstrDefExt     = _T("");
            oFileName.nMaxFileTitle   = 64;
            oFileName.lpstrFileTitle  = szFileTitle;
            oFileName.lpstrTitle      = NULL;
            //[ファイルを開く]ダイアログボックスを作成
            GetOpenFileName(&oFileName);
 
            if( oFileName.lpstrFile[0] )
                //指定されたファイルに対して、指定された操作を実行
                ShellExecute(hWnd, _T("open"), oFileName.lpstrFile, NULL, NULL, SW_SHOWDEFAULT );
			break;
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
		break;
	}

	return 0;
}

リソースの作成

リソースは、メニュー、IDR_MENU1を追加し、メニューの項目を以下のように入力します。(表3-1./図3-1.)

表3-1.IDR_MENU1のメニュー項目のIDとキャプションの組み合わせ
ID キャプション
ID_40001 バージョン(&A)
ID_40002 終了(&X)
ID_40003 開く(&O)

図3-1.メニューリソースの中身

メニューリソースの中身

プログラムの実行

リソースの設定が終われば、プログラムの実行が可能です。プログラムを実行すると、メニューのあるウィンドウが起動します。(図3-2.)

図3-2.プログラム実行結果

プログラム実行結果

メニューから「ファイル」を選ぶと、「開く(O)」という項目があるので、これを選択します。(図3-3.)

図3-3.「開く」メニューの選択

「開く」メニューの選択

すると、ファイルダイアログが出現します。(図3-4.)

図3-4.ファイルダイアログの出現

ファイルダイアログの出現

更に、このプロジェクトが入っているフォルダ内で、このプログラムの実行ファイルである「.exe」ファイルを見ると、以下のように、アイコンが作成したものと変わっていることがわかります。(図1-8.)

図1-8.アイコンの変更

アイコンの変更

プログラムの仕組み

ファイルダイアログの設定

このプログラムのポイントは、ファイルダイアログの出現部分です。ファイルダイアログを出現させるには、まず114行目で宣言されたOPENFILENAME構造体の値、oFileNameに、必要なデータを設定します。(155行目~166行目)

OPENFILE構造体の宣言
OPENFILENAME oFileName;

構造体のデータの中身の詳細は、省略しますが、lpstrFilterで開くファイルの拡張子(この場合は、.DOC)を指定し、lpstrFileに、ファイル名を受け取る配列関数を指定しています。

oFileNameの中身
oFileName.lStructSize     = sizeof( OPENFILENAME );
oFileName.hwndOwner    = hWnd;
oFileName.lpstrFilter       = _T("DOC Files\0*.doc;\0All Files(*.*)\0*.*\0\0");
oFileName.nFilterIndex    = 1;
oFileName.lpstrFile         = szFileName;
oFileName.nMaxFile        = MAX_PATH;
oFileName.Flags             = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
oFileName.lpstrDefExt     = _T("");
oFileName.nMaxFileTitle   = 64;
oFileName.lpstrFileTitle    = szFileTitle;
oFileName.lpstrTitle        = NULL;

ファイルダイアログを開く

これらのパラメータをもとに、ファイルダイアログを開くのが、168行目のGetOpenFileName関数です。パラメータとして、oFileNameのアドレスを引数として与えると、ファイルダイアログが開きます。

ファイルダイアログの起動
GetOpenFileName(&oFileName);

以上で、ファイルダイアログが出現するまでの処理は終了です。続いて、ファイルダイアログで、ファイルが指定された時の処理について説明していくことにしましょう。

ファイル名の取得

ファイルダイアログで開かれたファイルの古パスのファイル名は、oFileName.lpstrFileTitleの中に格納されます。したがって、この文字列を見れば、何のファイルが指定されてかがわかります。サンプルでは、170行目で、ファイル名の取得の有無を確認し、それをShellExecute関数(172行目)で実行しています。このサンプルでは、ファイルの拡張子に「.DOC」を指定しているため、WORD2003形式のファイルが開け、PCにMicrosoftOfficeがインストールされていれば、起動されて、そのドキュメントが開くようになっています。