こんにちは。
ビットマップボタン作成しようと、以下のプログラムを書きました。
if(!m_BmpBtn1.SubclassDlgItem(IDC_BUTTON5, this))
return(FALSE);
m_BmpBtn1.SetButtonStyle(BS_PUSHBUTTON|BS_OWNERDRAW);
m_BmpBtn1.LoadBitmaps(IDB_BITMAP1);
m_BmpBtn1.SizeToContent();
ビルド時にエラーは無いのですが、実行しようとすると、以下のメッセージボックスが出ます。
---------------------------
Microsoft Visual C++ Debug Library
---------------------------
Debug Assertion Failed!
Program: ...d Settings\toshimasa\デスクトップ\hatsuon13\Debug\hatsuon.exe
File: wincore.cpp
Line: 321
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
---------------------------
中止(A) 再試行(R) 無視(I)
---------------------------
おそらく、プログラムのどこかが間違っていると思うのですが…。
どうか、よろしくお願いします。
開発環境 Windows XP、VC++6.0、MFC
MFC遣いではありませんが…
> File: wincore.cpp
> Line: 321
まずは指定された場所を見るべきかと。
なにやら
CWnd::Attach()で問題になっているようですが…
指定された場所を見ると、
ASSERT(FromHandlePermanent(hWndNew) == NULL);
// must not already be in permanent map
とありました。
どんなときに、ここに引っかかるのかわかりません…。
新しくビットマップボタンだけを貼り付けたプログラムを作ると、エラーは出ません(ちゃんと貼り付けられました)。
書き忘れてましたが、問題のプログラムはダイアログベースで、ビットマップボタンを三枚貼り付けようとしています。
> 指定された場所を見ると
そこだけ見せられても推測で答えなきゃならんよ。
> どんなときに、ここに引っかかるのかわかりません…。
m_BmpBtn1.SubclassDlgItem
を実行中に発生しているのですか?
というかデバッガでどの処理のとき発生したか調べればいいじゃんか。
IDC_BUTTON5をウィザードでコントロールの変数m_BmpBtn1に
既にしているでしょ?
あれってサブクラス化で既存のウィンドウのメッセージ処理が
自分のプログラムで行えるようにしてある。
つまり二重にサブクラス化しているんじゃないの?
Windowsって二重にサブクラス化出来るようには考えられていない。
でも二重にサブクラス化してもエラーにならないし、できないわけじゃない。
というのも考えられていないので二重にサブクラス化しているか
Windowsがチェックすら出来ないからね。
だからASSERTで自分のプログラムが使用中(パーマネントマップに存在する)であることを指摘している。
指摘されたとおり、二重にサブクラス化していたようです。
if(!m_BmpBtn1.SubclassDlgItem(IDC_BUTTON5, this))
return(FALSE);
の部分を削除すると、最初のエラーは出ず、ビットマップボタンが貼り付けられました。
しかし、プログラムを終了すると、以下のエラーメッセージが出ます。
---------------------------
Microsoft Visual C++ Debug Library
---------------------------
Debug Assertion Failed!
Program: ...d Settings\toshimasa\デスクトップ\hatsuon13\Debug\hatsuon.exe
File: afx.inl
Line: 122
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
---------------------------
中止(A) 再試行(R) 無視(I)
---------------------------
指定された場所を見ても、さっぱりわかりません…。
どうか、よろしくお願いします。
m_BmpBtn1.UnsubclassWindow() しちゃってるとか。。
本題とは関係ないが、実行時エラーとデバッグアサートは別物。
混同すべきではありません。
デバッグアサートで引っ掛かったら、「再試行(R)」を押して、
コールスタックを見てみましょう。
> m_BmpBtn1.UnsubclassWindow() しちゃってるとか。。
そんなことしてませんよ!
ただ、
CDialog::OnCancel();
にブレークポイントを置いて、デバッグ実行しても問題の場所にたどり着けませんでした。
だから、RAPTさんが
「デバッグアサートで引っ掛かったら、「再試行(R)」を押して、
コールスタックを見てみましょう。」
と書いておられますよ。
その通りにやってみましたか?
タイミングの問題で現象が起きているとしたら
途中にブレークポイントを置いてしまうとタイミングが変わってしまうので
現象が変わっているかもしれません。
今、提示されている情報から教えてくれと言われても
皆、想像でしか物が言えないのでどんぴしゃりを期待する方が無理と言うもの
だと思いますけれど。
出ている以上、問題があるんでしょうから地道に追いかけるしか無いと思いますよ。
「再試行(R)」を押して、コールスタックを見てみると、
CString::GetData() line 122 + 34 bytes
CString::~CString() line 208 + 8 bytes
CHatsuonDlg::~CHatsuonDlg() + 71 bytes
が追加されていました。
終了するときに文字列操作なんてしてませんよ…。
CHatsuonDlgのデストラクタでCStringを使っていないならば、CHatsuonDlgの
CString型のメンバ変数の開放時にアサーションに引っ掛かっているのでは
ないでしょうか。
CHatsuonDlgの生成〜解放間に、CString型メンバ変数に対して
1. NULLで初期化
2. NULLを代入
3. memset()やZeroMemory()などでゼロ埋め (……さすがに有り得ないか)
のいずれかを行っていませんか?(どれもやってはならない処理)
色々指摘されても
そのことについてのみ書くだけだな。
こっちからしてみれば
他人のプログラムだ。
>CString::GetData() line 122 + 34 bytes
>CString::~CString() line 208 + 8 bytes
>CHatsuonDlg::~CHatsuonDlg() + 71 bytes
>終了するときに文字列操作なんてしてませんよ…。
なんていわれても知らんよ。
それに
>指定された場所を見ても、さっぱりわかりません…。
閲覧者にVC++6.0のサービスパック不明のafx.inlのソース見ろっていうのか。
閲覧者に面倒なことさせるのかよ。
他人のプログラムなのに詳細なしでわかるかけないだろ。
結局はあなた自身が調べないとわからんよ。
>終了するときに文字列操作なんてしてませんよ…。
そんなこといわれても。
デストラクタなんて自動で呼ばれるんだから。
それにassertの意味判ってる?
見てないだろ?
見ていてこの質問だとしたら嫌がらせか。
assertは変数や引数が変な値であることを発見し指摘してくれる処理だ。
でも、変な値にしてしまう原因は別の場所である。
この手の問題は、閲覧者は手助けはしても
あなたのプログラムなのであなたが見つけ出しあなたが直すのだ。
もしも、メモリ破壊でほかの変数のメモリ領域を壊している処理があったら、
見つけ出すのは大変だよ。
とりあえず、手元のVC++6.0では…
> // CString
> _AFX_INLINE CStringData* CString::GetData() const
> { ASSERT(m_pchData != NULL); return ((CStringData*)m_pchData)-1; }
です。
yoh2さんの書かれているパターンみたいですね。
> CHatsuonDlg::~CHatsuonDlg() + 71 bytes
でクリックしたら、該当行に行きませんかね?
CHatsuonDlgのメンバ変数が見られるだけかも知れませんが。
コントロール変数だったりとか…
ひとつ訂正。
>1. NULLで初期化
>2. NULLを代入
>3. memset()やZeroMemory()などでゼロ埋め (……さすがに有り得ないか)
リファレンスには書かれていないようですが、VC6SP6では1と2で問題が
起こらないようです。(空文字列になる)
ソースを読み間違えていました。申し訳ないです。
となると3かメモリ破壊なのかなぁ。
できました。
int nResponse = dlg.DoModal();
の前の
m_pMainWnd = &dlg;
を手違いでコメントアウトしていました…。
皆さんには、質問がわかりにくかったのをお詫びすると同時に、協力して下さったことに御礼申し上げます。
ツイート | ![]() |