////////////////////////////////////////////////////////////////////////////////
開発環境 : Visual C++ 6.0
動作環境 : Windows 98 Second Edition
MFC使用 MDIベース
////////////////////////////////////////////////////////////////////////////////
今、私のプログラムでは、ファイルを保存したり開いたりするのに
一番最初に開かれるフォルダがMyDocumentです。
これをexeファイルがあるフォルダにしたいのですが、
簡単にできるのでしょうか。
今、MFCのどの部分がそれを決めているのか、探している
ところなのですが、なかなか見つからず苦労しております。
もし、どなたかわかる方がいらっしゃれば、よろしくお願いします。
コモンダイアログで簡単にできるはずです。
オープンダイアログとか。
ファイル開く/保存で、CFileDialog(あるいはその派生クラス)を使っているのであれ
ば、DoModal関数でダイアログボックスを開く前に、データメンバm_ofn(OPENFILENAME
型)のメンバlpstrInitialDirに、最初に開きたいフォルダ名を設定してあげます。
ご質問の勝手な解釈です
このご質問に、最低2種類含まれているようです
1.EXEの場所の取得方法はどうすれば良いか?
>これをexeファイルがあるフォルダにしたいのですが、
こんな関数で取得できます(引数は俺の勝手な記述)
GetCurrentDirectory(sizeof(dir_str),dir_str);
2.「保存」や「開く」で起動される関数はどこにある?
回答方法が2つあるんです
1つは、
「コーディングしているのはあなたなので、わかりません、
ソース提示してください」
2つめは、
「リソース エディタ から 保存・開くのリソースIDを調べ
クラスウィザードで関連付けされている関数を調べてください」
つまりAppWizardが生成した関数のどの部分をいじれば良いかわからない
と言うことでは無いでしょうか
ドキュメントクラスのSerializeを調べてみてはいかがでしょうか
アイスケーターさん、monkeyさん、woodさん、みなさん、貴重な
お返事、ありがとうございました。
早速、みなさんの助言をもとに調べてみようと思います。
>1.EXEの場所の取得方法はどうすれば良いか?
> >これをexeファイルがあるフォルダにしたいのですが、
>
> こんな関数で取得できます(引数は俺の勝手な記述)
> GetCurrentDirectory(sizeof(dir_str),dir_str);
GetCurrentDirectory はその名のとおりカレントディレクトリを取得するものであり、
exeファイルのあるフォルダを取得するものではありません。
exe を直接ダブルクリックして起動した場合は、exeのあるフォルダがカレントになりま
すが、
たとえばショートカットを使って起動した場合は、ショートカットのプロパティの
”作業フォルダ”がカレントになります。
また、exe 実行中に SetCurrentDirectory でカレントはいくらでも変更できます。
GetModuleFileName で exe のフルパスが得られるので、_splitpath を使うなりして、
exe のフォルダを抽出してください。
これは失礼しました、フォローありがとうございます
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);
}
pathStrの内容を確認されましたか?
ひょっとして\が抜けてませんか
そもそも、ファイル選択ダイアログはどうやって出していますか?
それが分からなければ答えようがないような。
たとえば ID_FILE_OPEN のメッセージハンドラがデフォルトのままなら、
MFCが勝手にダイアログを出しますが、このダイアログでの初期フォルダを
任意に設定したいということでしょうか?
その場合、SetCurrentDirectory ではできませんでした。(SDIならできた。)
メッセージハンドラを独自のものに変えて、自分でダイアログを出す必要が
ありそうです。
(他にも方法があるかもしれませんが。)
文字バッファの領域を適切なものに変えたほうがいいかもしれません。それと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();
みなさん、ご丁寧な説明、大変申し訳ないです。Blueさんに至っては
コードまで書いていただきとても参考になりました。
Blueさんのコードに従ってやってみたのですが、やはりダメのようでした。
デバッグで見る限りでは、うまくパスが入っているのですがカレントディレクトリは
MYDOCUMENTのままでした。
実はファイル選択のダイアログについては何も行っておりません。CFileDialogなどは
あまり扱った経験がなく、通常、MFCが作ってくれるダイアログを初めから
exeファイルがあるところにできないものかと思っておりました。
今思えば、アイスケーターさんやmonkeyさんが始めに指摘されていたことも
このことだったのではと思います。
実は、目的のプログラムは「ファイルをexeファイルがあるディレクトリに保存する」
という作業が極端に多いのでなんとかならないものかと思っておりました。
一度、プログラムを実行させたあとにディレクトリを変えるという作業は
ほとんどないので、常に、保存時にexeファイルがあるところを開いてくれる
というものでも全く構わないという状況です。
もう少し調べてみます。
>通常、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 で動作確認済み)
>(VC6ではコメントアウトしなくても動きましたが一応。
>VC7.1ではコメントアウトが必要でした。)
VC6でコメントアウトしなくても動いたのは、
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
の前に、独自のメッセージハンドラのエントリ
ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
が追加されたからでした。
(VC7.1ではうしろに追加されていた。)
ということで、基本的にコメントアウトは必要です。
失礼しました。。。
さっきの続きで
pathStr += *.txt;
CFileDialog dlg( TRUE, TXT, pathStr);
dlg.DoModal();
としたらいかがでしょう