こんばんわ、VC勉強中の初心者+です。
ある画像を自動で保存できるようなプログラムを作ろうと思っています。
その前段階として、フォルダ選択ダイアログでフォルダのパスを取得し、
コードの中で適当なファイル名をフォルダのパスと連結させて画像を保存させようと
おもいましたが、うまくセーブするファイル名ができません。
コードは以下のとうりです。
//フォルダ選択ダイアログのコード
CString Foldername;//フォルダのパスを入れる。
void Caaa::bbb(){
BROWSEINFO bInfo;
LPITEMIDLIST pIDList;
CString str;
CString str2;
// BROWSEINFO構造体に値を設定
bInfo.hwndOwner = AfxGetMainWnd()->m_hWnd;
bInfo.pidlRoot = NULL;
bInfo.pszDisplayName = str.GetBuffer(MAX_PATH);
bInfo.lpszTitle = _T(フォルダの選択);
bInfo.ulFlags = BIF_RETURNONLYFSDIRS;
bInfo.lpfn = NULL;
bInfo.lParam = (LPARAM)0;
pIDList = ::SHBrowseForFolder(&bInfo);
if(!(pIDList == NULL))
{
::SHGetPathFromIDList(pIDList, str2.GetBuffer(MAX_PATH))
Foldername = str2;
str.ReleaseBuffer();
::CoTaskMemFree( pIDList );
}
}
//ファイル名連結
void Caaa::ccc(){
CString Filename = 001.bmp;
CString Savename;
Savename = Foldername + \\ + Filename;
...略
}
デバックで見る限り、FoldernameにはD:\123456789という値が
入っていて、SavenameはD:\123456789\001.bmpとなる予定が
\001.bmpになり、Foldernameが連結されませんでした。
なにが悪いのかわからず困っています。
どうかご教授のほどお願いします。
環境は VC++6.0SP4 WinXP_SP1 SDIで作っています。
> デバックで見る限り、FoldernameにはD:\123456789という値が入っていて、
どこで見ました? 連結の直前?
# デバックではありません。デバッグ(debug)です。
勘ですが、+演算子よりもCString::Format()を使うといいかも。
Savename.Format( %s\\03d.bmp, Foldername, cnt );
という感じに。
str2 を ReleaseBuffer してないようだけど。
ReleaseBuffer しないうちに、他のオブジェクトにコピーしても大丈夫なんだっけ?
あと、パス名の連結には PathCombine とか PathAppend が便利。
> ReleaseBuffer しないうちに、他のオブジェクトにコピーしても大丈夫なんだっけ?
文字列長を確定していないので、operator+等のメソッドが正確に動かなくなっていま
す。
operator=はOKぽい。(文字列長不確定の情報もコピーするがw)
CString::GetBuffer-MSDN
http://www.microsoft.com/japan/msdn/library/default.asp?
url=/japan/msdn/library/ja/wcemfc/htm/cstring_14.asp
わざわざ CString 使ったのが敗因かな。
しれっと TCHAR str2[MAX_PATH]; で十分でわないかと。
> TCHAR
よくみたら微妙ですな。
> bInfo.lpszTitle = _T(フォルダの選択);
> CString Filename = 001.bmp;
> Savename = Foldername + \\ + Filename;
_Tマクロ使うんだか使わないんだか。
> あと、パス名の連結には PathCombine とか PathAppend が便利。
私は_splitpath,_makepathつかってました。(しかもCString::GetBuffer使ってw)
皆様、レスどうもです。
フォルダ選択ダイアログのコードは他のサイトからの引用です。お許し願います。
初心者なもので、文字列等はCStringを多用しています。
str2のReleaseBufferは入れるとエラーになってしまいます。
「strcore.cppの512行?(裏覚え)でエラー」みたいなのですが、何がなんだかです。
ReleaseBufferを削除したらエラーが出なくなったので必要ないとおもいました。
そこが原因なのでしょうか?
あとデバッグは連結の後で見ています。
以上です。また今日すこしがんばってみます。
# どーでもいーけど「裏覚え」ってナニ?
# 「うる覚え」のこと?
# どっちも間違い。 正しくは「うろ覚え」
> ReleaseBufferを削除したらエラーが出なくなったので必要ないとおもいました。
それはヒドイ。
エラーが出なくなった=正しくなった ではありません。
取りあえず食ってくれた だけのこと。 オナカ壊すかもしんないけど。
> strcore.cppの512行
CString::ReleaseBuffer(int nNewLength)の
> ASSERT(nNewLength <= GetData()->nAllocLength);
ですかね。
(そこらへんでASSERTIONが出そうなところはここぐらい。)
ReleaseBufferの引数にMAX_PATHより大きな値または-2以下の値を設定しているのでしょ
うか?
皆様のアドバイスで無事解決いたしました。
ReleaseBufferしないうちに代入したのがいけないみたいです。
ReleaseBufferしてから代入したらうまくいきました。
しかしなぜ、ReleaseBufferしないうちに代入したらいけないのかが
まだわかりません。
追伸、Wincore.cppの2666行でエラーがでます。
原因は何なのでしょうか?
CString s1, s2;
strcpy( s1.GetBuffer( 10 ), test );
s2 = s1;
s2.ReleaseBuffer();
みたいなことをするとアサートがでました。
> CString::ReleaseBuffer(int nNewLength)の
> > ASSERT(nNewLength <= GetData()->nAllocLength);
で GetData()->nAllocLengthの値が0でした。
CString::operator=の中で、
>m_pchData = stringSrc.m_pchData;
>InterlockedIncrement(&GetData()->nRefs);
の処理の時に文字列長が不確定でのままの状態が悪さをしているようです。
> 追伸、Wincore.cppの2666行でエラーがでます。
これは、ここに書かれているソースでは判断が付きません。(Wndクラス関連)
> ASSERT(hWndStop == NULL || ::IsWindow(hWndStop));
がなにを示しているか読み取ってください。
ASSERT(式)
式がTRUEならば、Debug Assertion Failed! のメッセージボックスを出す。
(デバッグモードのみ)
詳しくはMSDN引いてください。
> 式がTRUEならば、Debug Assertion Failed! のメッセージボックスを出す。
めちゃくちゃちがってました。逆ですた。
式がFALSE(偽)ならば、Debug Assertion Failed! のメッセージボックスを出す。
> しかしなぜ、ReleaseBufferしないうちに代入したらいけないのかが
> まだわかりません。
そういう仕様だから。
# 厳密なところはソースを読めば良い。
ちゃんとMSDNに、CString::GetBuffer()/GetBufferSetLength()を使ったら、
他のCStringクラスのメソッドを使用する前にReleaseBuffer()しろと
書いてあります。
> 追伸、Wincore.cppの2666行でエラーがでます。
> 原因は何なのでしょうか?
不正なコードを書いたから。
仕様外のことをしたら、何が起こるかわからない。何も保証されない。
だって、設計者の想定外のことをしているのだから。
PCが爆発しても文句は言えない。