ファイルの「保存」「開く」ではじめに開かれるディレクトリ

[戻る]
はまち 2004/09/18(土) 07:22:52
////////////////////////////////////////////////////////////////////////////////
    
    開発環境 : Visual C++ 6.0
    動作環境 : Windows 98 Second Edition
          MFC使用  MDIベース

////////////////////////////////////////////////////////////////////////////////

今、私のプログラムでは、ファイルを保存したり開いたりするのに
一番最初に開かれるフォルダがMyDocumentです。
これをexeファイルがあるフォルダにしたいのですが、
簡単にできるのでしょうか。
今、MFCのどの部分がそれを決めているのか、探している
ところなのですが、なかなか見つからず苦労しております。
もし、どなたかわかる方がいらっしゃれば、よろしくお願いします。

アイススケーター 2004/09/18(土) 08:39:44
コモンダイアログで簡単にできるはずです。
オープンダイアログとか。

monkey 2004/09/18(土) 08:45:23
ファイル開く/保存で、CFileDialog(あるいはその派生クラス)を使っているのであれ
ば、DoModal関数でダイアログボックスを開く前に、データメンバm_ofn(OPENFILENAME
型)のメンバlpstrInitialDirに、最初に開きたいフォルダ名を設定してあげます。

wood 2004/09/18(土) 09:05:53
ご質問の勝手な解釈です
このご質問に、最低2種類含まれているようです

1.EXEの場所の取得方法はどうすれば良いか?
 >これをexeファイルがあるフォルダにしたいのですが、

 こんな関数で取得できます(引数は俺の勝手な記述)
 GetCurrentDirectory(sizeof(dir_str),dir_str);

2.「保存」や「開く」で起動される関数はどこにある?
 回答方法が2つあるんです

 1つは、
 「コーディングしているのはあなたなので、わかりません、
  ソース提示してください」
 2つめは、
  「リソース エディタ から 保存・開くのリソースIDを調べ
  クラスウィザードで関連付けされている関数を調べてください」

 つまりAppWizardが生成した関数のどの部分をいじれば良いかわからない
 と言うことでは無いでしょうか

 
 ドキュメントクラスのSerializeを調べてみてはいかがでしょうか

はまち 2004/09/18(土) 09:27:39
アイスケーターさん、monkeyさん、woodさん、みなさん、貴重な
お返事、ありがとうございました。
早速、みなさんの助言をもとに調べてみようと思います。

isshi 2004/09/18(土) 09:42:59
>1.EXEの場所の取得方法はどうすれば良いか?
> >これをexeファイルがあるフォルダにしたいのですが、
>
> こんな関数で取得できます(引数は俺の勝手な記述)
> GetCurrentDirectory(sizeof(dir_str),dir_str);
GetCurrentDirectory はその名のとおりカレントディレクトリを取得するものであり、
exeファイルのあるフォルダを取得するものではありません。
exe を直接ダブルクリックして起動した場合は、exeのあるフォルダがカレントになりま
すが、
たとえばショートカットを使って起動した場合は、ショートカットのプロパティの
”作業フォルダ”がカレントになります。
また、exe 実行中に SetCurrentDirectory でカレントはいくらでも変更できます。

GetModuleFileName で exe のフルパスが得られるので、_splitpath を使うなりして、
exe のフォルダを抽出してください。

wood 2004/09/18(土) 10:05:10
これは失礼しました、フォローありがとうございます

はまち 2004/09/18(土) 11:42:09
CDocumentから派生したCXXXDocのコンストラクタで以下のように
してみたのですがうまくいきません。SetCurrentDirectory(pathStr)
でのpathStrにはパスは入っているのですが。何か、おかしな部分があるのでしょうか。

CXXXDoc::CXXXDoc()
{
    CString pathStr;
    LPTSTR fileName = pathStr.GetBuffer(100);
    GetModuleFileName(NULL,fileName,100);

    char drive[100];
    char dir[100];
    char fname[100];
    char ext[100];

    _splitpath( fileName, drive, dir, fname, ext );

    pathStr = drive;
    pathStr += dir;
    BOOL bJudge = SetCurrentDirectory(pathStr);

}

アイススケーター 2004/09/18(土) 13:22:14
pathStrの内容を確認されましたか?
ひょっとして\が抜けてませんか

isshi 2004/09/18(土) 13:51:58
そもそも、ファイル選択ダイアログはどうやって出していますか?
それが分からなければ答えようがないような。

たとえば ID_FILE_OPEN のメッセージハンドラがデフォルトのままなら、
MFCが勝手にダイアログを出しますが、このダイアログでの初期フォルダを
任意に設定したいということでしょうか?
その場合、SetCurrentDirectory ではできませんでした。(SDIならできた。)
メッセージハンドラを独自のものに変えて、自分でダイアログを出す必要が
ありそうです。
(他にも方法があるかもしれませんが。)

Blue 2004/09/18(土) 17:20:24
文字バッファの領域を適切なものに変えたほうがいいかもしれません。それとcharの配
列で領域をとる場合は初期化したほうがいいでしょう。

以下のコードはCStringを使ってexeのディレクトリ名を取得しています。(起動確認はし
ていませんw)

    CString strPathName;  // exeのフルパス

    // exeのパスを取得
    ::GetModuleFile( NULL, strPathName.GetBuffer( _MAX_PATH ), sizeof( TCHAR ) 
* _MAXPATH );
    // 文字列長の調整
    strPathName.ReleaseBuffer();

    CString strDrive;    // ドライブ名
    CString strDir;      // ディレクトリ名

    // ドライブ名、ディレクトリ名の取得
    ::_splitpath( strPathName, strDrive.GetBuffer( _MAX_DRIVE ), 
strDir.GetBuffer( _MAX_DIR ), NULL, NULL );
    // 文字列長の調整
    strDrive.ReleaseBuffer();
    strDir.ReleaseBuffer();

    CString strModuleDir;  // exeディレクトリ名

    // exeのディレクトリ名を作成
    ::_makepath( strModuleDir.GetBuffer( _MAX_PATH ), strDrive, strDir, NULL, 
NULL );
    // 文字列長の調整
    strModuleDir.ReleaseBuffer();

はまち 2004/09/18(土) 21:45:33
みなさん、ご丁寧な説明、大変申し訳ないです。Blueさんに至っては
コードまで書いていただきとても参考になりました。

Blueさんのコードに従ってやってみたのですが、やはりダメのようでした。
デバッグで見る限りでは、うまくパスが入っているのですがカレントディレクトリは
MYDOCUMENTのままでした。

実はファイル選択のダイアログについては何も行っておりません。CFileDialogなどは
あまり扱った経験がなく、通常、MFCが作ってくれるダイアログを初めから
exeファイルがあるところにできないものかと思っておりました。
今思えば、アイスケーターさんやmonkeyさんが始めに指摘されていたことも
このことだったのではと思います。

実は、目的のプログラムは「ファイルをexeファイルがあるディレクトリに保存する」
という作業が極端に多いのでなんとかならないものかと思っておりました。
一度、プログラムを実行させたあとにディレクトリを変えるという作業は
ほとんどないので、常に、保存時にexeファイルがあるところを開いてくれる
というものでも全く構わないという状況です。

もう少し調べてみます。

isshi 2004/09/18(土) 23:56:37
>通常、MFCが作ってくれるダイアログを初めから
>exeファイルがあるところにできないものかと思っておりました。
これについては私はわかりませんが、上で私が書いた
>メッセージハンドラを独自のものに変えて、自分でダイアログを出す必要
>がありそうです。
のやり方を書いておきます。
(とりあえず、「開く」の場合について)

ClassWizard のメッセージマップの「クラス名」で CXxxApp、
「オブジェクトID」で ID_FILE_OPEN、「メッセージ」で COMMAND
を選択し、「関数の追加」ボタンを押す。

メンバ関数名を指定してOKボタンを押す。

「コード編集」ボタンを押し、上で指定したメンバ関数の中身を
以下のように記述する。

void CXxxApp::OnFileOpen() 
{
    // TODO: この位置にコマンド ハンドラ用のコードを追加してください
    CString pathStr;
    LPTSTR fileName = pathStr.GetBuffer(100);
    GetModuleFileName(NULL,fileName,100);

    char drive[100];
    char dir[100];
    char fname[100];
    char ext[100];

    _splitpath( fileName, drive, dir, fname, ext );

    pathStr = drive;
    pathStr += dir;

    CFileDialog dlg(TRUE);  // コンストラクタのデフォルト引数は省略しています。
                            // 必要に応じて適切な引数を指定すること。
                            // とりあえずこれでも動きます。
    dlg.m_ofn.lpstrInitialDir = pathStr;
    if (dlg.DoModal() == IDOK){
        OpenDocumentFile(dlg.GetPathName());
    }
}


Xxx.cpp の

BEGIN_MESSAGE_MAP(CTestMDIApp, CWinApp)
  ...
  // 標準のファイル基本ドキュメント コマンド
  ...
  ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)  // *1
  ...
END_MESSAGE_MAP()

の *1 の行をコメントアウトする。
(VC6ではコメントアウトしなくても動きましたが一応。
VC7.1ではコメントアウトが必要でした。)


(WinXP Home SP1, VC6SP6, MDI で動作確認済み)

isshi 2004/09/19(日) 00:07:26
>(VC6ではコメントアウトしなくても動きましたが一応。
>VC7.1ではコメントアウトが必要でした。)
VC6でコメントアウトしなくても動いたのは、
  ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
の前に、独自のメッセージハンドラのエントリ
  ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
が追加されたからでした。
(VC7.1ではうしろに追加されていた。)
ということで、基本的にコメントアウトは必要です。
失礼しました。。。

アイススケーター 2004/09/19(日) 20:14:18
さっきの続きで

pathStr += "*.txt";

CFileDialog    dlg( TRUE, "TXT", pathStr);
dlg.DoModal();

としたらいかがでしょう

はまち 2004/09/19(日) 22:42:52
isshiさん、アイススケーターさん、お返事ありがとうございました。

isshiさんのコードでうまく移動させることができました。CFileDialogとは
このように簡単にコード上で書いていいのですね。てっきり、
新しくクラスを作成していろいろやらなければならないと
思っていたのですが、思っていたよりもずっと簡単でした。

あとは、これを保存時のファイル選択にするだけだと思い、いろいろ
やっているのですが、なぜかうまくいきません。
私はメニューバーとツールバーからファイル保存のメッセージ、ID_FILE_SAVE
を出すようにしており、このメッセージハンドらをCXXXAppに持たせ、CFileDialog
の宣言を
CFileDialog dlg(FALSE); 
のようにすればよいと思い、やってみているのですが、メッセージハンドラ
void CXXXApp::OnFileSave()
{

}
の中にデバッグ時に入ってきてくれません。
同様にID_FILE_SAVE_ASでもやってみてもダメです。
ID_FILE_SAVEなどの場合、何か特別な処理が必要なのでしょうか。

伺ってばかりで大変申し訳ないです。もし、簡単にわかるようであまり
お手数をおかけしないようであれば、お教えください。よろしくお願いします。

isshi 2004/09/20(月) 00:11:47
よく調べていなかったのですが、ID_FILE_SAVE, ID_FILE_SAVE_AS では
ID_FILE_OPEN と同じようにはいかないようです。
ちょっと時間がなくてすぐに解決策を提示することはできません。

直接参考になるかどうかは分かりませんが、参考まで。
http://www.microsoft.com/japan/msdn/library/default.asp?
url=/japan/msdn/library/ja/vclib/html/_mfcnotes_tn022.asp

Blue 2004/09/20(月) 01:21:24
仕組みとかよくわかりませんが、ドキュメントクラスならうまくいきますよ。

はまち 2004/09/20(月) 07:42:01
[[解決]]
isshiさん、Blueさん、お返事、ありがとうございました。

できました!ありがとうございます!Blueさんの仰るよう、Documentクラス
ハンドラではできました。私も未だその仕組みはわかりませんが、
これで大きく前進することができそうです。
まだ、アイスケーターさんが仰っていたCFileDialogのコンストラクタの
引数などは試していませんが、MSDNを見ながら進めていこうと思います。

きっとみなさん、お忙しい中での発言だったのではと思います。
アイスケーターさんやmonkeyさん、woodさんにも合わせてお礼申し上げます。
ありがとうございました。

古いスレッドには追加発言できません。