WinXP、VC6、ダイアログベースで作成しています。
Create()を使用してモードレスダイアログを表示させているのですが、
2つのモードレスダイアログを同様の方法で記述したにも関わらず、
片方のみアクセス違反で表示できない状況となり困っています。
<ソースファイル(メイン)>
CMainDlg::CMainDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMainDlg::IDD, pParent)
{
/*(CModeless* )*/m_pModeless = new CModeless( this );
}
CMainDlg::~CMainDlg()
{
/*(CModeless* )*/m_pModeless = NULL;
}
void CMainDlg::OnBtnOpen()
{
/*(CModeless* )*/m_pModeless->Create();
}
<ソースファイル(モードレスダイアログ)>
BOOL CModeless::Create()
{
return CDialog::Create( CModeless::IDD, m_pParent );
//ここでアクセス違反となります
}
ちなみに、新しくダイアログを作成して同様の記述を行った場合
作成したダイアログが表示でき、元々作成していたダイアログがアクセス違反となりま
す。
色々調べてますが原因がわかりません。
お手数ですがアドバイスをよろしくお願いいたします。
CDialog::Create()の呼び出しでアクセス違反の起きる理由は山ほど考えられ
ますので、それだけでは答えようがありません。
CDialog::Create()の中に潜っていって、具体的にアクセス違反を起している
行のコードを教えて下さい。
あと、アクセス違反が起きる前に Assertion Failed とか発生していませんか?
発生してるようならその行のコードも教えて下さい。
bunさん
ご回答ありがとうございます。
返信が遅くなり申し訳ありません。
>CDialog::Create()の中に潜っていって、具体的にアクセス違反を起している
>行のコードを教えて下さい。
「潜っていく」とは具体的にどのような方法をとれば良いのでしょうか?
素人質問ですみません・・
>あと、アクセス違反が起きる前に Assertion Failed とか発生していませんか?
>発生してるようならその行のコードも教えて下さい。
これは発生していないようです。
また、Create()の前にGetSafeHwnd()を追加すると「AFXWIN2.INL」の
_AFXWIN_INLINE HWND CWnd::GetSafeHwnd() const
⇒ { return this == NULL ? NULL : m_hWnd; }
でアクセス違反となります。
Create()はこれまで使ってきたことはあったのですが、
こういった症状は初めてでパニックになってます。
お手数ですがよろしくお願いいたします。
>「潜っていく」とは具体的にどのような方法をとれば良いのでしょうか?
ステップ実行していく…ということかと。
今回の場合だと、ステップインで呼び出し先へと追いかけていくことになりますかね。
> return CDialog::Create( CModeless::IDD, m_pParent );
> //ここでアクセス違反となります
のreturnの行にブレークポイントを置いて実行。
ブレークしたらステップイン(F11キーだったかな)で進めていって、実際にアクセス違反
が発生する場所のソースコード名と行番号を調べて下さい。
ということでしょう。
# MFCのソースをインストールしていないとステップインできませんので…インストールし
ていない場合はインストールしてからになります。
名前が化けたままでした(TT
上のは私です(TT
>また、Create()の前にGetSafeHwnd()を追加すると「AFXWIN2.INL」の
Create()の前だと…ハンドルがまだ作成されていないとかいうことはないですかね???
うーーん、
VC6.0は、ステップがあまり効かないし、暴走するときがあります。
関数の中まで見れるかな?
ブレークで一つ一つ調べていくのがいいかと思いますね。
まぁー金銭的に厳しいですが、新しいVCを買ったほうがいいですね。
>また、Create()の前にGetSafeHwnd()を追加すると「AFXWIN2.INL」の
>_AFXWIN_INLINE HWND CWnd::GetSafeHwnd() const
>⇒ { return this == NULL ? NULL :
これ、いいヒントですね。
一つ一つ段階的にブレークしていってどこから
this == NULL → m_hWnd == NULLになるか見て
おかしな処理をしていないか見てみるしかないように思います。
瀬戸っぷさん
ITOさん
ありがとうございます。
Create()前の値を見ると、
m_pModelessの値が0x00000003{CModeless hWnd=???}
となってます。
良く意味はわかりませんが、このhWnd=???がいけないような
気は、します・・。
追記
うーーん?
Create()の前ですか、なら違いますね。
あとは、
・CModeless::IDDがもうひとつのダイアログとダブっていないか?
・m_pParentがLULLになっていないか。
ですかね。
>m_pModelessの値が0x00000003{CModeless hWnd=???}
>となってます。
そうですね。
ばにらさんの結果より遅くなってしまいました。
これは何が原因なのでしょうか?
どういった確認をすればよいのでしょうか?
> m_pModelessの値が0x00000003{CModeless hWnd=???}
「0x00000003 なんて位置のアドレスを指している」+「奇数アドレス」となると、
どっかでバッファオーバーランしている可能性をまず疑う。
>どういった確認をすればよいのでしょうか?
これはどうですか?
> あとは、
> ・CModeless::IDDがもうひとつのダイアログとダブっていないか?
> ・m_pParentがLULLになっていないか。
> ですかね。
Create()の前のthisポインタの値をチェックして何か気づくことはないですか?
Create()を呼ぶと、ざっと以下の処理が走ります。
1) ダイアログテンプレートを適用してリソースの表示
2) ダイアログの初期化
a) DDX/DDVを利用したメンバ変数の割り当てとデータチェック
b) OnInitDialog()内の処理
この膨大な処理のどこでもアクセス違反は起き得ます。
思いつく限り列挙すると、
1) CModeless::IDDのリソースIDを持ったダイアログリソースが存在しない
2) DDX/DDVで関連づけているコントロールIDのリソースが存在しない
(例) DDX_Control(pDX, IDC_BTN1, m_Btn1);
において、IDC_BTN1がダイアログリソース上に存在しない
3) CDialog::OnInitDialog()を呼ぶ前にDDXメンバ変数にアクセスしている
(例) 2)の例の実装があるとして、
BOOL CModeless::OnInitDialog()
{
m_Btn1.SetWindowText(Test); // <- アクセス違反
CDialog::OnInitDialog();
}
4) そもそも、CModeless::OnInitDialog()内の処理にバグがある
:
(などなど)
可能性がありすぎるので絞りきれないわけです ^^;
遅くなってすみません。
>どっかでバッファオーバーランしている可能性をまず疑う。
この場合もうお手上げですかね?
まだアプリケーション作り始めなので、最初から作り直すのもアリかなと
考え始めてます。
(解決策になるかはわかりませんが。)
>Create()の前のthisポインタの値をチェックして何か気づくことはないですか?
thisの値は 0x0012fb7c で、異常があるようには見えません。
>bunさん
ありがとうございます。
チェックできるところからやっていこうかと思います。
>> どっかでバッファオーバーランしている可能性をまず疑う。
> この場合もうお手上げですかね?
VS2008 とかだと「デバッグ」->「ブレークポイントの作成」->「新しいデータ ブレーク
ポイント」で指定メモリアドレスが書き換えられた瞬間とコード場所を掴める。のだが、
VC6にこの機能あったっけ?
上記が無理なら
CMainDlg::CMainDlg(...) {
/*(CModeless* )*/m_pModeless = new CModeless( this );
m_pModelessBackup = m_pModeless;
}
CMainDlg::PreTranslateMessage(...) {
if (m_pModelessBackup != m_pModeless) { // 自分の知らない所で値が変わった
AfxMessageBox(_T(直前操作でバッファオーバーランされたかも));
}
:
}
等でもして、大体で探っていくしかないかも