- ベストアンサー
fopen(書き込みモード)でファイルが作成されない
Visual StudioでWindowsプログラミングをしています。 RESULT CALLBACK WndProc(HWND hwnd, UINT imsg, WPARAM wp, LPARAM lp){ … switch(imsg){ case WM_COMMAND: switch(LOWORD(wp)) { case ID_FILEOPEN: FileSet(hwnd); break; case ID_WRITE: if((fp_test=fopen("test_data.dat","w"))==NULL) exit(0); fputs("******",fp_test); fclose(fp_test); break; … } return 0; } のようにメニューからファイルの読み書きを行わせたいと思っています。 プログラムを実行してすぐにWRITE部分を行うと、 ファイルは正常に作られ、書き込みもできています。 ところが、先にFILEOPENを行うと、その後WRITEが正しく動かず、 ファイル自体が作成されません。 ファイルオープンに失敗すれば、終了するはずですが、それもしません。 FILEOPENで呼び出しているFileSet関数は以下です。 void FileSet(HWND hwnd){//ファイルの選択 char filePath[MAX_PATH]; char fileFolder[MAX_PATH]; char *pt,*ptEnd,*ptEndNext; if(OpenFiles(hwnd)==1){ pt = FileName; ptEnd = strchr(FileName,'\0'); ptEndNext = ptEnd + 1; if(ptEnd){ int nLength; if(*(ptEndNext) == '\0'){//ファイルが1つしか選択されていない strcpy( filePath, FileName ); FileOperation(filePath); //ファイルオープンとデータの平滑化 }else{ //複数選択 strcpy( fileFolder, FileName );//フォルダ名の取得 nLength = strlen(fileFolder); if(fileFolder[nLength]!='\\') strcat(fileFolder, "\\"); while(*(ptEndNext) != '\0'){ strcpy(filePath, fileFolder); //パス名を作成 strcat(filePath, ptEndNext ); //ファイル名を連結 FileOperation(filePath); ptEnd = strchr( ptEndNext, '\0' ); //次のファイルを探す ptEndNext = ptEnd + 1; } } } } } FileSet関数内で呼んでいるFileOperationは以下です。 テキストデータを数値に変換し、indataという構造体配列に代入しています。 indata,numはグローバル変数です。 void FileOperation(char *filePath, int b){//ファイルオープンとデータスケーリング int i,j; double datawork; char work[10]; if((fp=fopen(filePath,"r"))==NULL)//ファイルオープン exit(0); for(i=0,j=0;(i<DATA_NUM) && (fscanf(fp,"%s",work)!=EOF);++i){//データ読み込み datawork = atof(work); indata[num].data[j] = (float)datawork/NORM; j++; } fclose(fp); datawork = 0; indata[num].number = num; strcpy(indata[num].fname,filePath); num++; } おそらくこのあたりに原因があるとは思うのですが、 自分ではわかりませんでした。 お力を貸していただければと思います。 WinXP SP3, VisualStudio 2005で作成しています。 説明不足な部分がありましたらすみません。 よろしくお願いいたします。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
多分関係ありませんが, if(fileFolder[nLength]!='\\') strcat(fileFolder, "\\"); この処理はおかしいような気がします. 「\ で終わっていれば何もせず, \ で終わっていない場合には \ を付ける」という処理をしたいのだと思いますが, \ で終わっている場合にも \ を付けるのではないでしょうか. 例えば fileFolder が "a" だと nLength は 1 になりますが, fileFolder[nLength] は '\0' ですよね.
その他の回答 (1)
- chie65536
- ベストアンサー率41% (2512/6032)
Windowsのコールバック関数は、リエントラントである事が要求されます。 しかし、Cの標準ライブラリ関数のfopenは、リエントラント関数である保証はありません。 もし、fopenが非リエントラントで実装されている場合、リエントラントである事が要求される関数内で使用すると、動作は未定義です。 つまり「RESULT CALLBACKと定義されたWndProc関数内では、fopen関数を使用すると、動作は未定義」と言う事です。 リエントラントでない実装のfopen関数をコールバック関数で使用した為、fopenは「予期せぬ動作」をします。それが「どんな動作」かは、誰にも判りません。 今回は「予期せぬ動作」として「ファイルも作らず、何もせず、エラーにもせず、何だか正体の判らないFILEへのポインタを返す」と言う動作をしました。 fopenがリエントラントでない場合については、以下の質問の、当方の回答を参照して下さい。 http://oshiete1.goo.ne.jp/qa4545663.html リエントラントである事が要求されるコールバック関数では、fopenの使用を避けCreateFile(API)を使用するか、fopenに再入しないようミューテックスを設けるなど、工夫が必要です。 ともかく、現状のままでは「fopenは使えない」と思って下さい。
お礼
回答ありがとうございました。 ファイルが作れないことに関しては自己解決いたしまして、 FILEOPENした時にカレントディレクトリが変更されていたようで、、 オープンしたファイルのあるディレクトリに、 ファイルはきちんと作成されていました。 書き込みファイル名を絶対パスで指定していなかったことと、 私の早とちりが原因でした。お騒がせいたしました。 リエントラント関数については、全く知識がありませんでした。 これから勉強したいと思います。 ありがとうございました。
お礼
回答ありがとうございました。 ファイルが作れないことに関しては自己解決いたしまして、 FILEOPENした時にカレントディレクトリが変更されていたようで、、 オープンしたファイルのあるディレクトリに、 ファイルはきちんと作成されていました。 書き込みファイル名を絶対パスで指定していなかったことと、 私の早とちりが原因でした。お騒がせいたしました。 ご指摘の部分ですが、確かに変な処理をしていますね…。 実行時に、予期せぬ動作などしなかったので、見過ごしていました。 修正したいと思います。ありがとうございました。