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で作成しています。
説明不足な部分がありましたらすみません。
よろしくお願いいたします。
No.1ベストアンサー
- 回答日時:
多分関係ありませんが,
if(fileFolder[nLength]!='\\')
strcat(fileFolder, "\\");
この処理はおかしいような気がします. 「\ で終わっていれば何もせず, \ で終わっていない場合には \ を付ける」という処理をしたいのだと思いますが, \ で終わっている場合にも \ を付けるのではないでしょうか.
例えば fileFolder が "a" だと nLength は 1 になりますが, fileFolder[nLength] は '\0' ですよね.
回答ありがとうございました。
ファイルが作れないことに関しては自己解決いたしまして、
FILEOPENした時にカレントディレクトリが変更されていたようで、、
オープンしたファイルのあるディレクトリに、
ファイルはきちんと作成されていました。
書き込みファイル名を絶対パスで指定していなかったことと、
私の早とちりが原因でした。お騒がせいたしました。
ご指摘の部分ですが、確かに変な処理をしていますね…。
実行時に、予期せぬ動作などしなかったので、見過ごしていました。
修正したいと思います。ありがとうございました。
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は使えない」と思って下さい。
回答ありがとうございました。
ファイルが作れないことに関しては自己解決いたしまして、
FILEOPENした時にカレントディレクトリが変更されていたようで、、
オープンしたファイルのあるディレクトリに、
ファイルはきちんと作成されていました。
書き込みファイル名を絶対パスで指定していなかったことと、
私の早とちりが原因でした。お騒がせいたしました。
リエントラント関数については、全く知識がありませんでした。
これから勉強したいと思います。
ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- Visual Basic(VBA) VBAのユーザーフォームのテキストボックスに入力制限をしたい 6 2022/11/15 08:28
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- Excel(エクセル) Excelにて、フォルダ内のTextファイルをマクロで統合すると文字化けしてしまう時の解消コード 4 2023/01/01 07:32
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- Visual Basic(VBA) ExcelのVBAコードについて教えてください。 1 2023/08/09 10:33
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- Excel(エクセル) VBA フォルダ見える化のコードについて 2 2023/06/19 15:04
- Visual Basic(VBA) batからexeを実行し戻り値を受け取る バッチからEXEの結果を受け取りたいのですが、 下記のバッ 1 2023/07/04 15:13
- Visual Basic(VBA) サブフォルダ(データ)にある複数の.xlsxファイルのSheet3のA2セルの値で01から左側をB2 2 2022/08/14 15:46
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VBSで指定行に挿入
-
バイナリファイルをテキストフ...
-
ファイル内のデータを1行削除...
-
改行までの一文字ずつのファイ...
-
fgetsで2行目から文字化け
-
テキストファイルの行数を取得...
-
VC++6でfgets関数の変わりにな...
-
複数テキストファイルを読み込...
-
DOSでメモ帳を開いても改行され...
-
巨大なテキストファイル(可変...
-
BCB 読み込み。
-
C/C++ ファイル入出力操作 (長...
-
続・EOF判定されない
-
C言語初心者の質問失礼します。
-
webアプリケーションでの画像フ...
-
フルパスから最後のディレクト...
-
分割コンパイルの#defineについて
-
バッファとは何ですか
-
マイクラでPythonのプログラミ...
-
FTPでputすると空ファイルが出...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
ファイル内のデータを1行削除...
-
テキストファイルの行数を取得...
-
バイナリファイルをテキストフ...
-
fgetsで2行目から文字化け
-
VBSで指定行に挿入
-
ファイルサイズ指定し、ファイ...
-
c言語 2つのファイルを行ご...
-
freadとfwrite
-
winsock recvでの文字化け
-
【VB.Net】バイト型配列に読み...
-
C言語での改行コードの扱いにつ...
-
fopen(書き込みモード)でファイ...
-
fortranで文字列を読み込む際の...
-
EOF判定されない
-
改行までの一文字ずつのファイ...
-
InternetReadFileで大きいファ...
-
freadでファイルを読み込んだ際...
-
C言語での採番について
-
複数テキストファイルを読み込...
-
C言語 バイナリファイルの読み...
おすすめ情報