• ベストアンサー

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で作成しています。 説明不足な部分がありましたらすみません。 よろしくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

多分関係ありませんが, if(fileFolder[nLength]!='\\')  strcat(fileFolder, "\\"); この処理はおかしいような気がします. 「\ で終わっていれば何もせず, \ で終わっていない場合には \ を付ける」という処理をしたいのだと思いますが, \ で終わっている場合にも \ を付けるのではないでしょうか. 例えば fileFolder が "a" だと nLength は 1 になりますが, fileFolder[nLength] は '\0' ですよね.

asatuge
質問者

お礼

回答ありがとうございました。 ファイルが作れないことに関しては自己解決いたしまして、 FILEOPENした時にカレントディレクトリが変更されていたようで、、 オープンしたファイルのあるディレクトリに、 ファイルはきちんと作成されていました。 書き込みファイル名を絶対パスで指定していなかったことと、 私の早とちりが原因でした。お騒がせいたしました。 ご指摘の部分ですが、確かに変な処理をしていますね…。 実行時に、予期せぬ動作などしなかったので、見過ごしていました。 修正したいと思います。ありがとうございました。

その他の回答 (1)

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.2

Windowsのコールバック関数は、リエントラントである事が要求されます。 しかし、Cの標準ライブラリ関数のfopenは、リエントラント関数である保証はありません。 もし、fopenが非リエントラントで実装されている場合、リエントラントである事が要求される関数内で使用すると、動作は未定義です。 つまり「RESULT CALLBACKと定義されたWndProc関数内では、fopen関数を使用すると、動作は未定義」と言う事です。 リエントラントでない実装のfopen関数をコールバック関数で使用した為、fopenは「予期せぬ動作」をします。それが「どんな動作」かは、誰にも判りません。 今回は「予期せぬ動作」として「ファイルも作らず、何もせず、エラーにもせず、何だか正体の判らないFILEへのポインタを返す」と言う動作をしました。 fopenがリエントラントでない場合については、以下の質問の、当方の回答を参照して下さい。 http://oshiete1.goo.ne.jp/qa4545663.html リエントラントである事が要求されるコールバック関数では、fopenの使用を避けCreateFile(API)を使用するか、fopenに再入しないようミューテックスを設けるなど、工夫が必要です。 ともかく、現状のままでは「fopenは使えない」と思って下さい。

asatuge
質問者

お礼

回答ありがとうございました。 ファイルが作れないことに関しては自己解決いたしまして、 FILEOPENした時にカレントディレクトリが変更されていたようで、、 オープンしたファイルのあるディレクトリに、 ファイルはきちんと作成されていました。 書き込みファイル名を絶対パスで指定していなかったことと、 私の早とちりが原因でした。お騒がせいたしました。 リエントラント関数については、全く知識がありませんでした。 これから勉強したいと思います。 ありがとうございました。

関連するQ&A