ファイル選択


ファイルの選択ダイアログ

この場では、多くのアプリケーションで見られるファイルの選択ダイアログを紹介します
これを用いることで、より確実にファイルを選択することができるようになります

通常、ファイルを読み込む時、ユーザーは必ずしも存在するファイルを指定するわけではなく
時には、存在しないファイルや無効な記号を間違って挿入するかもしれないのです
本来なら、アプリケーションがこれらのエラーチェックをしなければなりませんが
ファイルの選択ダイアログでは、こういったエラー処理も代行してくれます
つまり、バッファに格納されるファイル名は安全なファイル名であることが保障されるのです

このダイアログを出すには GetOpenFileName() 関数を使います
このダイアログは、読み込むファイルを選択する時に使用します

BOOL GetOpenFileName(LPOPENFILENAME lpofn);

lpofn には、初期化情報を格納した OPENFILENAME 構造体 へのポインタを指定します
ユーザーが OK ボタンを押せば 0 以外、そうでなければ 0 が返ります

OPENFILENAME 構造体は次のような定義になっています
typedef struct tagOFN { // ofn 
    DWORD         lStructSize; 
    HWND          hwndOwner; 
    HINSTANCE     hInstance; 
    LPCTSTR       lpstrFilter; 
    LPTSTR        lpstrCustomFilter; 
    DWORD         nMaxCustFilter; 
    DWORD         nFilterIndex; 
    LPTSTR        lpstrFile; 
    DWORD         nMaxFile; 
    LPTSTR        lpstrFileTitle; 
    DWORD         nMaxFileTitle; 
    LPCTSTR       lpstrInitialDir; 
    LPCTSTR       lpstrTitle; 
    DWORD         Flags; 
    WORD          nFileOffset; 
    WORD          nFileExtension; 
    LPCTSTR       lpstrDefExt; 
    DWORD         lCustData; 
    LPOFNHOOKPROC lpfnHook; 
    LPCTSTR       lpTemplateName; 
} OPENFILENAME;
lStructSize には、この構造体のサイズを指定します
hwndOwner は、ダイアログボックスの親ウィンドウのハンドルを指定します

hInstance は、ダイアログボックステンプレートを用いる場合に
テンプレートを含むモジュールのインスタンスハンドルを指定します

lpstrFilter には、選択対象のファイルをフィルタリングするための文字列を指定します
この文字列は、表示文字列\0フィルタ文字列 という形で指定します
表示文字列はダイアログのリストボックスに表示される文字列で
フィルタ文字列は、フィルタパターンを(これは MS-DOS と同じ)指定します
例えば、"Text (*.txt)\0*.txt" とすれば、拡張子が txt のファイルのみが表示されます

この組み合わせを連続することで、リストボックスにその組み合わせの情報が加算されます
文字列の終端を知らせるには NULL 文字を2つ連続して指定します

lpstrCustomFilter は、ユーザー定義のフィルタ文字列バッファへのポインタを指定します
これは、lpstrFilter 同様に表示文字列とフィルタ文字列の組み合わせです
システムは、選択されたフィルタパターンをこのバッファに保存します
表示文字列は変わりませんが、フィルタは最後に保存されたものになっているでしょう

nMaxCustFilter には、lpstrCustomFilter のバッファサイズを指定します
この長さは、最低でも 40 文字分以上のサイズを指定しなければなりません
lpstrCustomFilter が NULL の場合は無視されます

nFilterIndex には、ダイアログの初期設定のフィルタインデックスを指定します
0 を指定すれば、ユーザー定義のカスタムフィルタを表します

lpstrFile は、ファイル名が格納される 256 文字以上のバッファへのポインタを指定します
このバッファに、選択されたファイルのフルパスが格納されます
nMaxFile には、lpstrFile が指すバッファサイズを指定します

lpstrFileTitle には、ファイルタイトルを格納するバッファへのポインタを指定します
ファイルタイトルとは、ドライブ名とディレクトリ名を除いた、ファイル自体の名前です
必要がない場合は NULL を選択してください
nMaxFileTitle には、lpstrFileTitle が指すバッファサイズを指定します

lpstrInitialDir は、初期のファイルディレクトリを表す文字列のポインタを指定します
このメンバが NULL の場合、選択ダイアログはカレントディレクトリを表示します
lpstrTitle には、ダイアログのタイトルバーに表示する文字列を指定します
NULL を指定すれば、デフォルトの文字がタイトルバーに表示されます

Flags は、ダイアログ作成フラグを指定します
このメンバには、以下の定数の組み合わせを指定することができます

定数解説
OFN_ALLOWMULTISELECT 「ファイル名」リストボックスで複数選択を可能にする
専用テンプレートを用いてダイアログを作成する場合
「ファイル名」リストボックスの定義に LBS_EXTENDEDSEL 値を入れる
このフラグを選択すると lpstrFile メンバが指すバッファに
ディレクトリへのパスと、選択された全てのファイル名
そして、ファイル名の間はスペースで区切られ格納される
OFN_EXPLORER フラグが設定されている場合は
それぞれ NULL 文字で区切られ、連続した NULL 文字で終わる
OFN_CREATEPROMPT 現在存在しないファイルを作成するかを求めるプロンプトを表示する
OFN_PATHMUSTEXIST と OFN_FILEMUSTEXIST フラグも含む
OFN_ENABLEHOOK lpfnHook で指定されたフック関数を有効にする
OFN_ENABLETEMPLATE hInstance が lpTemplateName メンバで指定された
ダイアログテンプレートを含むリソースのインスタンスであることを示す
OFN_ENABLETEMPLATEHANDLE hInstance メンバがロード済みのダイアログボックステンプレートを含む
メモリブロックを指していることを表す
このフラグが指定されている場合、lpTemplateName は無視される
OFN_EXPLORER 新しいエクスプローラスタイルのダイアログボックスの
カスタム化方法を用いることを示す
OFN_FILEMUSTEXIST 既存のファイル名しか入力を許さない
OFN_PATHMUSTEXIST フラグも含む
OFN_HIDEREADONLY 「読み取り専用」チェックボックスを隠す
OFN_LONGNAMES 古いダイアログボックスのために、長いファイル名を用いる
OFN_EXPLORER が設定されている場合は常に長い名前になる
OFN_NOCHANGEDIR ダイアログボックスは、現在のディレクトリを
ダイアログボックスが呼び出された時のディレクトリに戻す
OFN_NODEREFERENCELINKS 選択されたショートカットファイル(.LNK)のパスとファイル名を
返すようにダイアログボックスに指示する
OFN_NOLONGNAMES 「ファイル名」リストボックスに長いファイル名を表示しない
OFN_NONETWORKBUTTON 「ネットワーク」ボタンを隠す
OFN_NOREADONLYRETURN 返されたファイルに対する「読み取り専用」チェックボックスに
チェックマークを付けない
OFN_NOTESTFILECREATE ダイアログボックスを閉じる前にファイルを作成しない
このフラグは、「変更不可で作成」ネットワーク共有ポイント上で
ファイルを保存する場合に指定する
OFN_NOVALIDATE 無効な文字が入ったファイル名を有効とみなす
OFN_OVERWRITEPROMPT 保存時に選択されたファイルが存在する場合
メッセージボックスが表示され上書きをするか確認する
OFN_PATHMUSTEXIST 有効なパス及びファイル名でなければ入力を許さない
OFN_READONLY ダイアログの「読み取り専用」チェックボックスをチェックすることを表す
OFN_SHAREAWARE ネットワーク共有違反が原因で OpenFile() 関数呼び出しが失敗した場合に
エラーを無視して所定のファイル名を返す
このフラグが指定されている場合には SHAREVISTRING に対する
登録メッセージが lParam パラメータで指定されたパスおよびファイル名に対する
NULL で終わる文字列のポインタと共にフック関数に送られる
フック関数は次のいずれかで応答しなければならない

OFN_SHAREFALLTHROUGH - ファイル名を表示する
OFN_SHARENOWARN - アクションなし
OFN_SHAREWARN - 標準警告メッセージを出す
OFN_SHOWHELP ヘルプボタンを表示する
このフラグを設定する場合、親ウィンドウを持たなければならない

nFileOffset は、lpstrFile が指す文字列内におけるパスの先頭から
ファイル名までの 0 から数えたオフセットを表します

nFileExtension は、lpstrFile が指す文字列内におけるパスの先頭から
ファイル名拡張子までの 0 から数えたオフセットを表します
lpstrDetExt が NULL であれば、終端の NULL 文字までのオフセットを指します
ユーザーがファイル名の最後の文字として "." を指定した場合は 0 になります

lpstrDefExt には、デフォルトの拡張子を表す文字列へのポインタを指定します
ユーザーが拡張子を入力しなかった場合、この拡張子が用いられます

lCustData は、フック関数に渡す追加データを指定します
lpfnHook には、フック関数へのポインタを指定します
lpTemplateName は、ダイアログテンプレートを使用する場合に、テンプレート名を指定します
#include <windows.h>
#define TITLE TEXT("Kitty on your lap")

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	static OPENFILENAME ofn = {0};
	static TCHAR strFile[MAX_PATH] , strCustom[256] = TEXT("Before files\0*.*\0\0");

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		ofn.lStructSize = sizeof (OPENFILENAME);
		ofn.hwndOwner = hWnd;
		ofn.lpstrFilter = 	TEXT("Text files {*.txt}\0*.txt\0")
					TEXT("HTML files {*.htm}\0*.htm;*.html\0")
					TEXT("All files {*.*}\0*.*\0\0");
		ofn.lpstrCustomFilter = strCustom;
		ofn.nMaxCustFilter = 256;
		ofn.nFilterIndex = 0;
		ofn.lpstrFile = strFile;
		ofn.nMaxFile = MAX_PATH;
		ofn.Flags = OFN_FILEMUSTEXIST;
		return 0;
	case WM_RBUTTONUP:
		GetOpenFileName(&ofn);
		SetWindowText(hWnd , strFile);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hwnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hwnd = CreateWindow(
			TEXT("KITTY") , TITLE ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL ,
			hInstance , NULL
	);

	if (hwnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}


このプログラムを実行し、クライアント領域を右クリックすれば
ファイルの読み込みダイアログが表示されます

ダイアログでファイルを指定すれば、指定したファイルのフルパスが
ウィンドウのタイトルバーに表示されるので、確認してください


名前を付けて保存

ファイルの読み込みダイアログと同じ要領で
ファイルを保存するダイアログボックスを使うことができます
保存用ダイアログには GetSaveFileName() 関数を用います

BOOL GetSaveFileName(LPOPENFILENAME lpofn);

lpofn には、初期情報を格納した OPENFILENAME 構造体へのポインタを指定します
ユーザーが OK ボタンを押したなら 0 以外、そうでなければ 0 が返ります
#include <windows.h>
#define TITLE TEXT("Kitty on your lap")

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	static OPENFILENAME ofn = {0};
	static TCHAR strFile[MAX_PATH];

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		ofn.lStructSize = sizeof (OPENFILENAME);
		ofn.hwndOwner = hWnd;
		ofn.lpstrFilter = 	TEXT("Text files {*.txt}\0*.txt\0")
					TEXT("All files {*.*}\0*.*\0\0");
		ofn.lpstrFile = strFile;
		ofn.nMaxFile = MAX_PATH;
		ofn.Flags = OFN_FILEMUSTEXIST | OFN_OVERWRITEPROMPT;
		return 0;
	case WM_RBUTTONUP:
		GetSaveFileName(&ofn);
		SetWindowText(hWnd , strFile);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hwnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hwnd = CreateWindow(
			TEXT("KITTY") , TITLE ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL ,
			hInstance , NULL
	);

	if (hwnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
このプログラムは、上のファイルを読み込むダイアログボックスのプログラムを改良したもので
代わりにファイルの保存ダイアログボックスを表示させます


GetOpenFileName()

BOOL GetOpenFileName(LPOPENFILENAME lpofn);

ファイルを開くダイアログボックスを表示します

lpofn - 初期化情報を格納した OPENFILENAME 構造体 へのポインタを指定します

戻り値 - ユーザーが OK ボタンを押せば 0 以外、そうでなければ 0 が返ります

GetSaveFileName()

BOOL GetSaveFileName(LPOPENFILENAME lpofn);

ファイル名をつけて保存ダイアログボックスを表示します

lpofn - 初期情報を格納した OPENFILENAME 構造体へのポインタを指定します

戻り値 - ユーザーが OK ボタンを押したなら 0 以外、そうでなければ 0 が返ります



前のページへ戻る次のページへ