質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

1843閲覧

WinAPI 文字列に関して

BeatStar

総合スコア4958

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2016/11/08 02:06

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に設定する文字列データをビット演算でビットが立っているものを追加する方法

宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

null文字「\0」を使うと、そこを文字の終端として扱うのがc++の基本です。
その先に何が書いてあっても文字列とはみなしません。
(GetOpenFileNameは\0を区切りとして扱う特殊なケースなのでややこしいですが)

C++にて文字列の途中でNULL文字「'\0'」を含むstd::stringのサンプル
string使うなら第二引数で文字数を指定すればいけるかも?すいません、やったことないので自信がありません。
sprintfの方も最初のnull文字が来ているところまでしか文字列として見ていないので、いろいろおかしくなっているでしょうね。

ひとまず、string型の第二引数で文字数指定する方法を試してみてください。

投稿2016/11/08 02:37

編集2016/11/08 02:38
ishi9

総合スコア1294

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

C++

1filter += string( "label" ); 2filter.push_back( '\0' ); 3filter += string( "*.ext" ); 4filter.push_back( '\0' ); 5```これでヌル文字を強制的に埋め込めます。何行も書くのが嫌なら、 6```C++ 7filter += string( "All [ *.* ]\t*.*\t\t" ); 8 9size_t i = 0; 10for( i = 0; i < filter.length(); i++ ){ 11 if( filter[i] == '\t' ){ 12 filter[i] = '\0'; 13 } 14} 15```と置換を利用する手もあります。 16 17どちらも嫌なら、 18```C++ 19#define STLFILTERSTR(a) (std::string((a), sizeof(a)-sizeof((a)[0]))) 20filter += STLFILTERSTR( "All [ *.* ]\0*.*\0\0" ) 21```なんて方法もあります。 22 23参考URL: 24http://stackoverflow.com/questions/164168/how-do-you-construct-a-stdstring-with-an-embedded-null 25http://stackoverflow.com/questions/17403066/strange-behavior-on-adding-0-to-stdstring

投稿2016/11/08 03:05

編集2016/11/08 03:25
majiponi

総合スコア1720

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

episteme

2016/11/08 03:53

// 置換 #include <algorithm> ... std::replace(filter.begin(), filter.end(), '\t', '\0');
majiponi

2016/11/08 04:41

ああ、そういえばそんなのもありましたね、ぱっと思い出せなかったのでつい古典的な方法で書いてしまいましたw 補足ありがとうです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問