C/C++ ( WindowsAPI実装 ) でやっています。
WindowsAPI で GetOpenFileName関数を使って "ファイルを開く" ダイアログを表示しようとしています。
一応最低限のものはできたのですが、フィルタが思ったように動きません。
C++
1 ofn.lpstrFilter = TEXT("画像ファイル (*.gif, *.jpg, *.jpeg, *.png, *.bmp)\0*.gif;*.jpg;*.jpeg;*.png;*.bmp\0") 2 TEXT("動画ファイル (*.mp4, *.flv, *.avi, *.wmv, *.mkv)\0*.mp4;*.flv;*.avi;*.wmv;*.mkv\0") 3 TEXT("音声ファイル (*.mp3, *.wav, *.3gp, *.3g2)\0*.mp3;*.wav;*.3gp;*.3g2\0") 4 TEXT("テキストファイル (*.txt, *.data, *.data)\0*.txt;*.dat;*.data\0") 5 TEXT("C/C++ (*.c, *.cc, *.cpp, *.h, *.hpp, *.lib, *.o, *.obj, *.dll, *.exe, *.rc, *.res)\0*.c;*.cc;*.cpp;*.h;*.hpp;*.lib;*.o;*.obj;*.dll;*.exe;*.rc*.res\0") 6 TEXT("Java (*.java, *.class, *.jar, *.manifest)\0*.java;*.class;*.jar;*.manifest\0") 7 ....; 8
のように直接渡すなら普通にうまくいくのですが、
汎用化するにはよくないと思っています。
( リスト部分が縦に長ったらしくなるため。 )
これをビット演算によって分岐させようと考えています。
ビット演算は「ロベールのC++教室」の「ビットでフラグ」にある
C
1#define BIT(n) ((unsigned int)1 << (num))
を埋め込み、
JPG_TYPE を BIT(1), PNG_TYPE を BIT(2) ... のように定義し、
C++
1// 引数 DWORD flag に ビットが詰まっているとする 2if( flag & JPG_TYPE ){ 3 // ここで "JPG [ *.jpg, *.jpeg ]\0*.jpg;*.jpeg\0" を追加 4}else if(...){ 5 6}
のようにしました。
C由来の char型だと追加が面倒なので C++ の std::string を使い、
C++
1string filter; 2 3filter += string( "JPG [ *.jpg, *.jpeg ]\0*.jpg;*.jpeg\0" ); 4
という感じで 追加します。
動くかどうかわからないので、ビット演算関連は省いて 直接 string filter に追加していくと
C++
1string filter; 2 3filter += string( "JPG [ *.jpg, *.jpeg ]\0*.jpg;*.jpeg\0" ); 4filter += string( "GIF [ *.gif ]\0*.gif\0" ); 5... // 省略 6
とやってみました。
すると、コンパイルが通り、動くのですが
拡張子のリスト部に 一つの文字列として
"JPG [ *.jpg, *.jpeg ]GIF [ *.gif ]PNG [ *.png ]..."
のようになってしまいます。
OPENFILENAME::lpstrFilterの型を見てみるとLPCTSTRとなっていました。
ビット演算で分岐 ( たとえば jpg, gif, mp3, mp4 を許可する 等のように ビットを立てた ものだけ 許可する ) し、
std::string で追加していって、
最後 ( "すべてのファイル [ . ]" ) まで入れた後に
OPENFILENAME::lpstrFilter に渡す...
っていうことは不可能なのでしょうか。
( 一応 C由来 の char型配列で
C
1 char strFilter[10000]; 2 3 sprintf( strFilter, "%s%s", strFilter, "image [ *.gif, *.jpg, *.jpeg, *.png, *.bmp ]\0*.gif;*.jpg;*.jpeg;*.png;*.bmp\0" ); 4 sprintf( strFilter, "%s%s", strFilter, "movie [ ... ]\0*.mp4\0" ); 5 sprintf( strFilter, "%s%s", strFilter, "All [ *.* ]\0*.*\0\0" ); 6 7 ofn.lpstrFilter = strFilter; 8
と試してみましたが、同じ結果でした。 )
呼び出し元 ( ウィンドウプロシージャ等 ) の問題ではなくOPENFILENAMEのメンバに対する問題だと
思うので 呼び出し元を省き、関数定義のみを提示します。
#include<string> // インデックス enum OPENFILEINDEX{ OF_INDEX_IMAGESET = 1, OF_INDEX_MOVIESET, OF_INDEX_SOUNDSET, OF_INDEX_TEXTSET, OF_INDEX_CPPSET, OF_INDEX_JAVASET, OF_INDEX_CSHARPSET, OF_INDEX_VBSET, OF_INDEX_DELPHISET, OF_INDEX_PYTHONSET, OF_INDEX_COMPRESSEDSET, OF_INDEX_EXCELSET, OF_INDEX_WORDSET, OF_INDEX_POWERPOINTSET, OF_INDEX_FONTSET, OF_INDEX_CURSORSET, OF_INDEX_GIF, OF_INDEX_JPG, OF_INDEX_PNG, OF_INDEX_BMP, OF_INDEX_MP4, OF_INDEX_MPG, OF_INDEX_FLV, OF_INDEX_AVI, OF_INDEX_WMV, OF_INDEX_MKV, OF_INDEX_MP3, OF_INDEX_WAV, OF_INDEX_3GP, OF_INDEX_3G2, OF_INDEX_TXT, OF_INDEX_DAT, OF_INDEX_DATA, OF_INDEX_SWF, OF_INDEX_EXE, OF_INDEX_DLL, OF_INDEX_JAVA, OF_INDEX_CLASS, OF_INDEX_JAR, OF_INDEX_HTML, OF_INDEX_CSS, OF_INDEX_JAVASCRIPT, OF_INDEX_VBS, OF_INDEX_VB, OF_INDEX_CS, OF_INDEX_BAT, OF_INDEX_PHP, OF_INDEX_PY, OF_INDEX_PYC, OF_INDEX_RB, OF_INDEX_PL, OF_INDEX_C, OF_INDEX_CC, OF_INDEX_CPP, OF_INDEX_O, OF_INDEX_OBJ, OF_INDEX_LIB, OF_INDEX_HEADER, OF_INDEX_ZIP, OF_INDEX_RAR, OF_INDEX_LZH, OF_INDEX_ISO, OF_INDEX_DOC, OF_INDEX_DOCX, OF_INDEX_XLS, OF_INDEX_XLSX, OF_INDEX_PPT, OF_INDEX_PPTX, OF_INDEX_ANI, OF_INDEX_CUR, OF_INDEX_ICO, OF_INDEX_TTF, OF_INDEX_OTF, OF_INDEX_LNK, OF_INDEX_URL, OF_INDEX_ALL }; // エラーコード #define OFDIALOG_ERROR_CANCELED (-1) #define OFDIALOG_ERROR_WRONGHNADLE (-2) #define OFDIALOG_ERROR_CANNOTFINDRES (-3) #define OFDIALOG_ERROR_INIT (-4) #define OFDIALOG_ERROR_CANNOTLOADRES (-5) #define OFDIALOG_ERROR_CANNOTLOADSTR (-6) #define OFDIALOG_ERROR_CANNOTLOCKRES (-7) #define OFDIALOG_ERROR_MEMALLOC (-8) #define OFDIALOG_ERROR_MEMLOCK (-9) #define OFDIALOG_ERROR_REGISTERMSGFAIL (-10) #define OFDIALOG_ERROR_STRUCT (-11) #define OFDAILOG_ERROR_BUFFER (-12) #define OFDIALOG_ERROR_INVALIDFILENAME (-13) #define OFDIALOG_ERROR_SUBCLASS (-14) #define OFDIALOG_ERROR_UNKNOWN (-15) using namespace std; // "ファイルを開く" ダイアログを表示する関数 int ShowOpenFile( HWND hWnd, int DefaultIndex, const char *DefaultDir, const char *DefaultFileName, char *result ){ OPENFILENAME ofn; string filter; // ファイル拡張子のフィルタ ( 文字列 ) char temp[MAX_PATH+1]; int tempIndex; if( DefaultIndex <= 0 ){ tempIndex = OF_INDEX_ALL; }else{ tempIndex = DefaultIndex; } // これをやらないと失敗する memset( &ofn, 0, sizeof(OPENFILENAME) ); // ここでビット演算し、ビットが立っているものを追加するという処理にしたい。 // ですが今はビット演算を知りたいのではなく 文字列追加について知りたいので。 filter += string( "image [ *.gif, *.jpg, *.jpeg, *.png, *.bmp ]\0*.gif;*.jpg;*.jpeg;*.png;*.bmp\0" ); filter += string( "movie [ ... ]\0*.mp4\0" ); filter += string( "All [ *.* ]\0*.*\0\0" ); ofn.lpstrFilter = strFilter; ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.nFilterIndex = tempIndex; // 最初に指定するインデックス ofn.lpstrInitialDir = DefaultDir; ofn.lpstrFile = temp; // 戻り値用 ofn.nMaxFile = MAX_PATH+1; // 戻り値の最大の長さ ofn.Flags = OFN_FILEMUSTEXIST; // フラグ if( GetOpenFileName( &ofn ) != 0 ){ strcpy( result, temp ); return 0; }else{ DWORD r =CommDlgExtendedError(); if( r == 0 ){ return OFDIALOG_ERROR_CANCELED; // キャンセルされた }else if( r == CDERR_DIALOGFAILURE ){ return OFDIALOG_ERROR_WRONGHNADLE; // 無効なウィンドウハンドルが指定された等でダイアログ生成失敗 }else if( r == CDERR_FINDRESFAILURE ){ return OFDIALOG_ERROR_CANNOTFINDRES; // リソースが見つからなかった }else if( r == CDERR_INITIALIZATION ){ return OFDIALOG_ERROR_INIT; // メモリ不足等によりダイアログ初期化失敗 }else if( r == CDERR_LOADRESFAILURE ){ return OFDIALOG_ERROR_CANNOTLOADRES; // リソースのロード失敗 }else if( r == CDERR_LOADSTRFAILURE ){ return OFDIALOG_ERROR_CANNOTLOADSTR; // 指定した文字列のロード失敗 }else if( r == CDERR_LOCKRESFAILURE ){ return OFDIALOG_ERROR_CANNOTLOCKRES; // 指定したリソースのロック失敗 }else if( r == CDERR_MEMALLOCFAILURE ){ return OFDIALOG_ERROR_MEMALLOC; // 内部の構造体用のメモリ割り当てに失敗 }else if( r == CDERR_MEMLOCKFAILURE ){ return OFDIALOG_ERROR_MEMLOCK; // ハンドルに関連付けられているメモリをロック失敗 }else if( r == CDERR_REGISTERMSGFAIL ){ return OFDIALOG_ERROR_REGISTERMSGFAIL; // コモンダイアログボックス関数が呼び出した RegisterWindowMessage 関数が、エラーコードを返した }else if( r == CDERR_STRUCTSIZE ){ return OFDIALOG_ERROR_STRUCT; // 該当するコモンダイアログボックス用の初期化構造体の lStructSize メンバが無効 }else if( r == FNERR_BUFFERTOOSMALL ){ return OFDAILOG_ERROR_BUFFER; // 構造体の lpstrFile メンバが指すバッファが小さすぎて、ユーザーが指定したファイル名を格納できない。lpstrFile バッファの最初の 2 バイトは、名前全体を受け取るために必要なサイズを TCHAR 単位で格納します。 }else if( r == FNERR_INVALIDFILENAME ){ return OFDIALOG_ERROR_INVALIDFILENAME; // ファイル名が無効 }else if( r == FNERR_SUBCLASSFAILURE ){ return OFDIALOG_ERROR_SUBCLASS; // メモリ不足のため、リストボックスのサブクラス化失敗 }else{ return OFDIALOG_ERROR_UNKNOWN; } } }
( enum と #define と 関数プロトタイプは ヘッダに、関数定義は cppファイルに記述していますが、わかりやすくするために一つにまとめています。 )
※ ofnは OPENFILENAMEのオブジェクトとします。
[ 環境等 ]
言語 : C/C++ ( Windows API 実装 )
コンパイラ : MinGW
知りたいこと: "ファイルを開く"ダイアログ用のOPENFILENAME::lpstrFilterに設定する文字列データをビット演算でビットが立っているものを追加する方法
宜しくお願い致します。
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。