dポイントプレゼントキャンペーン実施中!

はじめまして、お世話になります。
『ダイアログで取得したファイル名』を、含むData構造体をファイルとして書き込む場合に限り、ファイルが出力されません。
Data構造体の文字列file_nameが『ダイアログで取得したファイル名』でなければ正常に出力されます。また、関数の返値や書き込み後のFILE構造体の中身を読み込んで調べたりしましたが、見る限りエラーはありませんでした。
開発ツールはMicrosoft Visual Studio 2005を使用しています。
どうか皆さんの知恵を貸してください! お願いします!

//ファイルとして出力する構造体
typedef struct
{
TCHAR file_name[256];
BYTE id;
}Data;

//ファイルを開くダイアログ
void OpenFile(HWND hWnd, TCHAR file_name[])
{
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = TEXT("png files {*.bmp}\0*.bmp\0") TEXT("all files {*.*}\0*.*\0\0");
ofn.lpstrFileTitle = (LPWSTR)file_name;
ofn.nMaxFileTitle = CHAR_SIZE;
ofn.lpstrFile = NULL;
ofn.Flags = OFN_FILEMUSTEXIST;
GetOpenFileName(&ofn);
}

//ファイルを書き込む
void SaveData(Data save_file[])
{
FILE *file;
errno_terr;
size_t write_num;

//書き込む
err = _tfopen_s(&file, TEXT("hoge.map"), TEXT("w+b"));
if(err != 0) return;
write_num = fwrite(save_file, sizeof(Data), 6, file);

//きちんと書き込めているか確かめる
Data chek_data[6];
fseek(file, 0L, SEEK_SET);
fread(chek_data, sizeof(Data), 6, file);
fclose(file);
}

A 回答 (16件中1~10件)

修正後のソースで確認しました。


こちらでは一応動作はしているようです。しかし、

> err = _tfopen_s(&file, TEXT("hoge.map"), TEXT("w+b"));

これでオープンしたファイル"hoge.map" の置かれるディレクトリが、
実行ファイルのあるディレクトリではなく、ビットマップのある
ディレクトリでした(コマンドラインから起動してチェックしてます)。

ひょっとして、書き換えたファイルは別のところにあって、
書き換わってなどいない古いファイルをチェックしていたりは
していませんか?

fopen_s ってそんなものでしたっけ?
時間がないので、フルパス指定でないときのファイル作成場所
については調べてないです。ごめんなさい。

to #9
> C99になってから、ブロックの先頭でなくても、変数宣言してよくなったようです(わたしも、つい最近まで知らなかった^^;)

お心遣いはありがたいのですが、知ってましたよ。
質問者さんの使っている VC++ 2005ではC99は完全にはサポートされておらず、
変数宣言に関するこれも未サポート事項の一つだからああ書いただけです。
    • good
    • 0
この回答へのお礼

ありがとうございます。おかげで解決できました。
どうやらGetOpenFileName()でファイルを開くと、カレントディレクトリが『開いたファイルがあるフォルダ』に移動してしまい、そこにファイルが出力されてしまうようです。ソースファイルの中身にばかり気をとられていて、全く気づきませんでした。
それと、書き込んで下さった皆さんのおかげで、いろいろと新しいことを知ることができ勉強になりました。ありがとうございます。

お礼日時:2007/09/03 14:46

★アドバイス


・OpenFile() 関数の次の1行のキャストは必要ない気がします。
 注意点⇒ofn.lpstrFileTitle = (LPWSTR)file_name;
 正しい⇒ofn.lpstrFileTitle = file_name;
 理由は file_name が TCHAR 型なので LPWSTR に強制するのはまずい気がするため確認を。
・あと Win32 API で同名の OpenFile() 関数があります。
 Cファイルでソースをコンパイルするとエラーがたくさん出すぎてコンパイル不能に陥りました。
 CPPファイルでソースをコンパイルするとやっとコンパイルできました。
 C++ は引数の個数や型が違うので別関数として識別したようです。
 出来ることなら Win32 API 関数と同じ名前の関数(OpenFile)は使わない方がいい気がします。
・ちなみに私は VC2003 でコンパイルしました。
 _tfopen_s() 関数がないので fopen() で代用してのコンパイルです。
 つまり #include <stdio.h> の次の行に
 typedef int errno_t;
 #define _tfopen_s(fp,s,t) (((*(fp) = fopen(s,t)) != NULL) ? 0 : -1)
 という2行を追加しました。→私は VC2005 を持っていないもので仕方がなしです。
・ソースをコンパイルしていて気づきましたが _tWinMain() 関数を使っていますね。
 どうも Unicode 文字でコンパイルしているようだね。
 もしかしたらここが原因でファイルに書き出せないのかもしれない。→今はまだ推測。
 そこで _tWinMain() を WinMain() に名前を変えてコンパイル・オプションで
 文字コードを Unicode からマルチバイト文字(シフトJIS)に変更してからコンパイルして下さい。
 これでどうなるのか補足して下さい。
・ちなみに私の環境では『hoge.map』ファイルが作成されました。
 作成された場所は exe ファイルと同じフォルダでした。
 ファイルのサイズは 1,542 バイトです。
 構造体メンバのアライメントを1バイト(/Zp1)にしておかないと正常に読み書きできないので
 こちらのオプションも確認して下さい。

最後に:
・WinMain() 関数のメッセージ・ループで PeekMessage() 関数を使っていますが CPU が暇なときに
 なにも処理していないせいか CPU 使用率が 100% にずっとなっています。
 もしかしたらゲーム・ループを組んでいるのかな?
 それだとしたら正しくないよ。組み方がおかしいです。
・正しくは下のようにループ内で PeekMessage() 関数を使ってメッセージがあったら分かりやすく
 GetMessage() 関数で取り出すようにして下さい。
 satou386 さんのループでは最初の一回しか PeekMessage() 関数でメッセージの有無を
 チェックできません。このままだと PeekMessage() 関数を使っている意味がないと思います。
・以上。

//●エントリポイント
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
 :
 省略
 :
 //メッセージループ
 MSG msg;
 
 for ( ; ; ){
  if ( !PeekMessage(&msg,NULL,0,0,PM_NOREMOVE) ){ // メッセージなし
   Sleep( 1 );  // 独自の処理
  }
  else if ( GetMessage(&msg,NULL,0,0) > 0 ){ // メッセージあり
   TranslateMessage( &msg );
   DispatchMessage( &msg );
  }
  else{
   return (int)msg.wParam;  // WM_QUIT、エラーが発生
  }
 }
}
    • good
    • 0

> 変数宣言に関するこれも未サポート事項…



ありゃ。。そうなんですか。それは失礼いたしました^^
ほんじゃ、satou386 さんの環境が特殊なんですね。fwrite() で書き込めないし(笑)
    • good
    • 0

void OpenFile(HWND hWnd, TCHAR file_name[])


{
OPENFILENAMEA ofn;
const char* filter="png files {*.bmp}\0*.bmp\0all files {*.*}\0*.*\0\0";
ZeroMemory(&ofn, sizeof(OPENFILENAMEA));
ofn.lStructSize = sizeof(OPENFILENAMEA);
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = filter;
ofn.lpstrFileTitle = file_name;
ofn.nMaxFileTitle = 255;
ofn.lpstrFile = NULL;
ofn.Flags = OFN_FILEMUSTEXIST;
GetOpenFileNameA(&ofn);
}
でもいきませんよね…?
    • good
    • 0

あっ、あと最後に、新しいソースのほうもまだ fread() 等して(シークして、ローカル配列に読み込んで、関数の戻り値も配列の中身もチェックしてないですけど(笑))ますね。

どうしても、fread() したければそれでもいいでしょうが、念のため、fwrite() 後に fflush() でも入れておいたらどうでしょうか?^^
    • good
    • 0

それから、『FILE構造体の中身を…』と質問の文章中にありますが、FILE 構造体のメンバを FILE を定義しているシステムのインクルードファイルなどで調べて、その各々をチェックしてみたという意味ですか?


http://www5c.biglobe.ne.jp/~ecb/c/12_02.html


_tfopen_s() というのを fopen("hoge.map", "w+b") に変えてみるとか。
しかし、すべて戻り値が正常なのにファイルができないとは。。。MicroSoft は不思議だ^^
    • good
    • 0

ちょっと思ったのは、fwrite() したあと、すぐ fread() してるので、stdio の内部バッファ内ですべて行えて、実際、ディスクへの書き出しが行われないのかとも思いましたが、それはないですよね。

。やっぱり(笑)オープンも成功し、書き出しも成功してるのに、そのオープンした名前のファイルができないのは、不思議だ。。。
    • good
    • 0

fwrite() などで書き込みが成功しているのにファイルができないというのは摩訶不思議ですねぇ^^ 知らないうちに unlink() みたいなことしてるのかしら(笑)



>『関数の途中で変数宣言をしたりしているので…』

C99になってから、ブロックの先頭でなくても、変数宣言してよくなったようです(わたしも、つい最近まで知らなかった^^;)
    • good
    • 0

#1の補足で提示されているエラーが再現できるというコードですけど


コンパイルすらできないのですが、本当にこれで再現できますか?

ちょこちょこ手直ししながらコンパイルしてみましたが、途中で
面倒になってやめてまいましたが


//●ファイルを開くダイアログ
void OpenFile(HWND hWnd, TCHAR file_name[])

Win32API に同名のものがあります。
windows.hをinclude しないでやるのならわからないでもありませんが
HWNDやTCHAR、BYTEなんかを使っているからそうではないですよね?
#提示プログラムではincludeしていませんが

また、関数の第二引数が TCAHR [] となっていますが

呼び出すところが
OpenFile(hWnd, g_save_data);
となっており、この g_save_data は

//●グローバル変数
Data g_save_data[DATA_NUMBER];

//●ファイルとして出力する構造体
typedef struct
{
TCHAR file_name[CHAR_SIZE];
BYTE id;
}Data;

です。

関数の途中で変数宣言をしたりしているので、C++モードでコンパイル
しているのでしょうが、いくらなんでもこの型違いは見逃してもらえない
と思います。

この回答への補足

分かり易いように変数名を変えたりした後に、コンパイルして確かめていなかったせいだと思います。申し訳ありません。
今度は同じツールなら確実に動くソースを作りました。コンパイルチェック済みですコピー&ペーストでそのまま使えます。ウインドウ枠内の『右クリックでファイルを開く』、『左クリックでファイル保存』です。

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

//●マクロ定数
#define CHAR_SIZE 256
#define DATA_NUMBER 6
#define CLASS_NAME TEXT("strClsName") //ウインドウクラスの名前
#define WINDOW_TITLE TEXT("my_window") //ウインドウ名
#define SCREEN_WIDTH 256 //画面・横
#define SCREEN_HEIGHT 256 //画面・縦

//●ファイルとして出力する構造体
typedef struct
{
TCHAR file_name[CHAR_SIZE];
BYTE id;
}Data;

//●グローバル変数
Data g_save_data[DATA_NUMBER];

//●ファイルを開くダイアログ
void OpenFile(HWND hWnd, TCHAR file_name[])
{
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = TEXT("png files {*.bmp}\0*.bmp\0") TEXT("all files {*.*}\0*.*\0\0");
ofn.lpstrFileTitle = (LPWSTR)file_name;
ofn.nMaxFileTitle = CHAR_SIZE;
ofn.lpstrFile = NULL;
ofn.Flags = OFN_FILEMUSTEXIST;
GetOpenFileName(&ofn);
}

//●ファイルを書き込む
void SaveData(Data save_file[])
{
FILE *file;
errno_terr;
size_t write_num;

//書き込む
err = _tfopen_s(&file, TEXT("hoge.map"), TEXT("w+b"));
if(err != 0)return;
write_num = fwrite(save_file, sizeof(Data), DATA_NUMBER, file);

//きちんと書き込めているか確かめる
Data chek_data[6];
fseek(file, 0L, SEEK_SET);
fread(chek_data, sizeof(Data), DATA_NUMBER, file);
fclose(file);
}

//●ウインドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_KEYDOWN: //Escキーで終了
if(wParam == VK_ESCAPE)
{
DestroyWindow(hWnd);
}
break;
case WM_LBUTTONDOWN:
SaveData(g_save_data);
break;
case WM_RBUTTONDOWN:
OpenFile(hWnd, g_save_data[0].file_name);
break;
case WM_DESTROY: //ウインドウが破棄された
PostQuitMessage(0);
break;
default:
return(DefWindowProc(hWnd, msg, wParam, lParam));
}
return TRUE;
}

//●エントリポイント
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
ZeroMemory(g_save_data, sizeof(g_save_data));

//ウインドウクラスの作成と登録
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszClassName = CLASS_NAME;
wc.hIconSm = NULL;
if(!RegisterClassEx(&wc))
{
return FALSE;
}

//ウインドウを生成
HWND hWnd;
int width = SCREEN_WIDTH + GetSystemMetrics(SM_CXDLGFRAME) * 2;
int height = SCREEN_HEIGHT + GetSystemMetrics(SM_CYDLGFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION);
hWnd = CreateWindow(CLASS_NAME, WINDOW_TITLE, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, hInstance, NULL);
if(!hWnd)
{
return FALSE;
}

//メッセージループ
MSG msg;
PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE );

while(WM_QUIT != msg.message)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}

補足日時:2007/09/02 13:22
    • good
    • 0

『GetOpenFileName() というのは…』って違うか^^ Java のファイルダイアログみたいに、ファイル選択ダイアログを表示するだけのことか^^



で、そのダイアログで、ユーザがファイルを選択して、<Save>ボタンみたいなのをクリックすると、SaveData() が呼び出されるように設定してるってことですよね、たぶん(笑)。失礼しました^^
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!