VC6 XP ダイアログベースです。
リストコントロール(レポート)に1行に4列ある。
1行に文字列を表示したい。
しかし、
以下の関数を実行すると死にます。
この関数は1行分の表示を行なう関数です。
死ぬ理由がわからなくて・・・
間違いはないはずなんですけど・・
誰か何かわかりませんか?
void CLogControlDlg::DispLogData_ListCtl(DWORD index, LOG_INFO *pLog)
{
LV_ITEM item;
CString str;
TIME_INFO *pTim;
// 表示する行番号の設定
item.iItem = index;
// 行の背景色を設定する
switch( pLog->ErrClass ){
case ERROR_PRIORITY_W:
item.lParam = RGB(255,255,0); // 黄
break;
case ERROR_PRIORITY_E:
item.lParam = RGB(255,0,0); // 赤
break;
default:
item.lParam = RGB(255,255,255); // 白
break;
}
// ログ番号表示(1列目)
item.iSubItem = 0;
item.mask = LVIF_TEXT | LVIF_PARAM;
str.Format(%5d,index+1);
item.pszText = str.GetBuffer(0x100);
str.ReleaseBuffer(-1);
m_LstCtl_Ctrl.InsertItem(&item);
// 時刻表示(2列目)
item.mask = LVIF_TEXT;
item.iSubItem = 1;
pTim = (TIME_INFO *)&(pLog->time);
str.Format(%04d/%02d/%02d %02d:%02d:%02d.%03d,pTim->year,pTim-
>month,pTim->day,pTim->hour,pTim->min,pTim->sec,pTim->ms);
item.pszText = str.GetBuffer(0x100);
str.ReleaseBuffer(-1);
m_LstCtl_Ctrl.SetItem(&item);
// 識別コード(3列目)
item.mask = LVIF_TEXT;
item.iSubItem = 2;
str.Format(%s,(1<=pLog->code && pLog->code<=6)? pSikibetuCode[pLog-
>code] : msg_Fumei );
item.pszText = str.GetBuffer(0x100);
str.ReleaseBuffer(-1);
m_LstCtl_Ctrl.SetItem(&item);
// ログ情報(4列目)
item.mask = LVIF_TEXT;
item.iSubItem = 3;
switch( pLog->code ){
case ERROR_ID_MAIN:
str.Format(%s,(0<=pLog->ErrType && pLog->ErrType<=2)? pMainData
[pLog->ErrType] : msg_Fumei );
break;
case ERROR_ID_RS232:
case ERROR_ID_RS422:
str.Format(%s,(0<=pLog->ErrType && pLog->ErrType<=17)? pRs232422
[pLog->ErrType] : msg_Fumei );
break;
case ERROR_ID_HOUCYOU:
str.Format(%s,(0<=pLog->ErrType && pLog->ErrType<=15)? pHoucyou[pLog-
>ErrType] : msg_Fumei );
break;
case ERROR_ID_TCPIP:
str.Format(%s,(0<=pLog->ErrType && pLog->ErrType<=4)? pTcpIp[pLog-
>ErrType] : msg_Fumei );
break;
case ERROR_ID_CMD:
str.Format(%s,msg_Cmd);
break;
default:
str.Format(%s,msg_CodeErr);
}
item.pszText = str.GetBuffer(0x100);
str.ReleaseBuffer(-1);
m_LstCtl_Ctrl.SetItem(&item);
}
回答とは違いますけど
この関数の どこで エラーが発生するのかデバッグはしてみましたか?
まずはそこからだと思いますが。
「死ぬ」とは、何を指していますか?
おそらく実行時エラーなのでしょうけど、そのエラーの内容は?
また、ステップ実行してみて、どこで死んでいるのかを突き止めてください。
すぐにわかる注意点としては…CString::GetBuffer はそうやって使うものじゃありませ
ん。
> 間違いはないはずなんですけど・・
十中八九、コードの間違いです。
すいません。内容が足りませんでした。
>「死ぬ」とは、何を指していますか?
実行時エラーのことです。
エラー内容は以下のとおりです。
Debug Assertion Failed!!
Program : D\xxx.exe
File : winctrl2.cpp
Line :547
For information on how your program can cause an assertion failere, see the
VisualC++ documentation on asserts.
(press Retry to debug the application)
この関数を実行中に死ぬわけではないのです。
関数を出た後に死にます。
しかし、この関数をコメントして実行すると死にません。
なぜ?やっぱりこの関数が原因なのでしょうか?
>CString::GetBuffer はそうやって使うものじゃありませ
ん。
どうやって使うのですか?
ではCString型の文字列の先頭アドレスを欲しい場合はどうするのですか?
使い方云々はとりあえず置いておいて
解放後の CString 操作でバッファが再確保されることがあるので、GetBuffer 関数から返さ
れるアドレスは、ReleaseBuffer 関数を呼び出した後では無効になります。CString のを長さ
を変更しないときは、バッファの再確保は行われません。
と、MSDNにもあるようにReleaseBufferした後で参照してるからでないのかな?
>と、MSDNにもあるようにReleaseBufferした後で参照してるからでないのかな?
今回のようにGetBufferで直接item.pszTextにポインタを代入してるので、
ReleaseBufferは必要ないということですか?
言われてみればそうですね・・・(戻り値をポインタに代入してるわけではないから)
CStringの使い方は死ぬ原因とは無関係ですよね。
上の記述でも、
item.pszTextに正確に代入されてますし・・・
> ReleaseBufferは必要ないということですか?
は必要ですよ。
まぁCStringでは色々面倒なので普通に TCHAR型配列を用意してやるほうが楽なのでは。
> str.Format(%5d,index+1);
> item.pszText = str.GetBuffer(0x100);
> str.ReleaseBuffer(-1);
TCHAR str[ 0x100 ];
_stprintf( str, %5d, index + 1 );
item.pszText = str;
訂正
> _stprintf( str, %5d, index + 1 );
_stprintf( str, _T( %5d ), index + 1 );
ほかのところは全部char型(TCHARを意識していないので)なので動き的には変わらないけ
ど。
>まぁCStringでは色々面倒なので普通に TCHAR型配列を用意してやるほうが楽なので
>は。
楽なのはわかってもす。
しかし、せっかくVCなのでできるだけC言語は使わないでやってみたかったもの
で・・・
関係ないかもですが、item.iItem にInsertの結果を代入せんくていいのかな?
ていうか、SetItemで適当なアドレスに値セットに行ってたりしない?
InsertItemの戻り値とindexが同じならいいですけど、ここがちがったりしない?
GetBufferで試してみました。やはりそこが原因ではなさそうです。
一応
> item.pszText = str.GetBuffer(0x100);
> str.ReleaseBuffer(-1);
> m_LstCtl_Ctrl.SetItem(&item);
item.pszText = str.GetBufferSetLength( str.GetLength() );
m_LstCtl_Ctrl.SetItem(&item);
str.ReleaseBuffer();
のほうがよさそうだけど。
ということで、
> 「死ぬ」
ということを明確にしてください。
もしかしてデバッグができないのでしょうか?
> 「死ぬ」ということを明確にしてください。
winctrl2.cppの547行目、
以下の関数のASSERTを実行すると死にます。
void CListCtrl::DrawItem(LPDRAWITEMSTRUCT)
{
ASSERT(FALSE);
}
この関数はいつコールされてるのでしょうか?
> この関数はいつコールされてるのでしょうか?
デバッグして、コールスタックをさかのぼってください。
意味がわからないのであれば、ある程度ブレイクポイントを仕掛けて、
F5実行でここまでは大丈夫、ここでASSERTが出る。じゃぁもう少しブレイクポイントの
範囲を狭くしてみようと言う行為をして、絞り込んでください。
あれ?
> void CListCtrl::DrawItem(LPDRAWITEMSTRUCT)
ってことは、もしかしたらオーナドローをするのにその処理がないってことかな?
リストビューのプロパティをいじったのであればその情報がほしいです。
(レポート形式にしたのしかワカラン)
で、将来的にカスタムドローかオーナドローをするようなんですが、そこら辺の情報も
ください。