読者です 読者をやめる 読者になる 読者になる

粗大メモ置き場

個人用,たまーに来訪者を意識する雑記メモ

Windows.hでファイル選択ダイアログ作成

どうもご無沙汰してます。
私事ですが最近アメリカに旅行にいって最高でした。
身バレしない程度に写真や出来事上げて自慢したいっす。はい。


では本題。

GUIでファイル選択ダイアログ作りたい

自作プログラムで参照するファイルをいちいち変更したり,引数として事前に与えるのが面倒なので
ファイル選択のGUIを実行時に出して選択できると非常に捗るかと思います。

今回作るものはこんなやつです。
f:id:ossyaritoori:20160926162829p:plain

意外と分量があるので関数として追加する時は
新たにファイルを作成しちゃってもいいと思います。

重要な部分

ウィンドウズ環境では Windows.h をインクルードして,
GetOpenFileName()という関数を呼ぶだけで済みます。

ところがどっこい,これに与えるファイルの作り方などがよくわからず,
結局ネットで例文を調べる羽目になることかと思います。

ひっかかった所

  • TCHAR が Unicode環境下でcharと扱いが異なる。

この関数ではPath名とファイル名を保存する型にTCHARを用いています。
マルチバイト文字を容認するUNUCODE環境下ではこれはcharと扱いが異なるので
そこらへんの区別をするところでもう一手間使わされました。


コード

gist使うべきか迷いましたがまぁ普通に貼るだけでいいでしょう。
はてなブログ以外のサービスを利用するべきな気がしてきた。

#include "Windows.h"

// 二度目呼び出すと最初のやつは消えます。注意してね。
char *GetNameFileOpen()
{
	HWND hWnd = NULL;
	static OPENFILENAME     ofn;
	static TCHAR            szPath[MAX_PATH];	// 初期フォルダ位置
	static TCHAR            szFile[MAX_PATH];   // 選択したファイル名 Staticなので関数外でも生きているが,もっかい呼ぶと死ぬ。
	static char				szFname[MAX_PATH];  // 出力用のファイル名 charの方が扱いやすいことがある

	if (szPath[0] == TEXT('\0')){
		GetCurrentDirectory(MAX_PATH, szPath);
	}
	if (ofn.lStructSize == 0){
		ofn.lStructSize = sizeof(OPENFILENAME);
		ofn.hwndOwner = hWnd;
		ofn.lpstrInitialDir = szPath;       // 初期フォルダ位置
		ofn.lpstrFile = szFile;       // 選択ファイル格納
		ofn.nMaxFile = MAX_PATH;
		ofn.lpstrFilter =
			TEXT("すべてのファイル(*.*)\0*.*\0");
		ofn.lpstrTitle = TEXT("ファイルを選択します。");
		ofn.Flags = OFN_FILEMUSTEXIST;
	}
	if (GetOpenFileName(&ofn)){
		MessageBox(hWnd, szFile, TEXT("ファイルを開く"), MB_OK);
	}
	else{
		// cancelled
		return "saved_image.bmp" ;
	}

	//ここからcharへと変換する
#ifdef UNICODE
	{
		int		nLen;

		//charに必要な文字数の取得
		nLen = ::WideCharToMultiByte(CP_THREAD_ACP, 0, szFile, -1, NULL, 0, NULL, NULL);
		if (szFname)
		{
			//変換
			nLen = ::WideCharToMultiByte(CP_THREAD_ACP, 0, szFile, (int)::wcslen(szFile) + 1, szFname, nLen, NULL, NULL);
			if (nLen == 0)
			{
				//error
				*szFname = NULL;
			}
		}
	}
#else
	{
		size_t	nLen;

		nLen = ::_tcslen(pszTchar) + 1;
		pszChar = new char[nLen];
		if (pszChar)
			::strcpy_s(pszChar, nLen * sizeof(char), pszTchar);
	}
#endif

	return szFname;
}