1

MFC で簡単なテスト アプリケーションを使用していますが、動作しません。メッセージ ハンドラは単に呼び出されません。ウィンドウはメッセージを受け取りますが、メッセージ マップに登録されているハンドラーを呼び出しません。

これは、ボタンの巨大なブロックを持ち、それらを押すとライブラリへのさまざまな呼び出しを行う、標準の mfc 単一ダイアログ アプリケーションです。ただし、ハンドラーは呼び出されません。

追跡しましたが、メッセージ マップが破損しているようです。次のような標準宣言があります。

BEGIN_MESSAGE_MAP(CommLib_test_x86Dlg, CDialog)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDCANCEL, &CommLib_test_x86Dlg::OnBnClickedCancel)
    ON_BN_CLICKED(IDOK, &CommLib_test_x86Dlg::OnBnClickedOk)
    ON_BN_CLICKED(IDC_BUTTON1, &CommLib_test_x86Dlg::OnBnClickedButton1)
    ON_BN_CLICKED(IDC_BUTTON2, &CommLib_test_x86Dlg::OnBnClickedButton2)
    ON_BN_CLICKED(IDC_BUTTON3, &CommLib_test_x86Dlg::OnBnClickedButton3)
    ON_BN_CLICKED(IDC_BUTTON4, &CommLib_test_x86Dlg::OnBnClickedButton4)
    ON_BN_CLICKED(IDC_BUTTON5, &CommLib_test_x86Dlg::OnBnClickedButton5)
    // many more buttons, but I commented the rest out for test
END_MESSAGE_MAP()

ON_WM_そして、最初の* に (つまり静的メソッドに)ブレークポイントを置いGetThisMessageMapてメッセージ マップの内容を見ると、最初のエントリは正しいのですが、残りはほとんど 0であり、配列のサイズは実際の定義と一致しません。 . デバッガーは値を次のように報告します

[0] {nMessage=274 nCode=0 nID=0 ...}
[1] {nMessage=0 nCode=0 nID=0 ...}
[2] {nMessage=0 nCode=19 nID=4206192 ...}
[3] {nMessage=55 nCode=0 nID=0 ...}
[4] {nMessage=0 nCode=0 nID=0 ...}
[5] {nMessage=0 nCode=0 nID=0 ...}
[6] {nMessage=0 nCode=0 nID=0 ...}
[7] {nMessage=0 nCode=0 nID=0 ...}
[8] {nMessage=0 nCode=0 nID=0 ...}
[9] {nMessage=0 nCode=0 nID=0 ...}
[10] {nMessage=0 nCode=0 nID=0 ...}
[11] {nMessage=0 nCode=0 nID=0 ...}
[12] {nMessage=0 nCode=0 nID=0 ...}
[13] {nMessage=0 nCode=0 nID=0 ...}
[14] {nMessage=0 nCode=0 nID=0 ...}
[15] {nMessage=0 nCode=0 nID=0 ...}

コードは、警告などなしで正常にコンパイルされます。

アプリケーションはプロジェクトの膨大なコレクションの一部であり、それらのプロジェクトはコンパイラ オプションを共有することに注意することが重要です。実際にビジュアル スタジオ プロジェクトを生成しますが、.vspropsファイルを使用する前です。私はしばらくプロジェクトを使用していませんでしたが、その間にコンパイラフラグが変更された可能性があります。

4

1 に答える 1

2

わかりました、見つけました。コンパイラ フラグは実際に変更されました。恐ろしい/vmgフラグが追加されました (他のライブラリで使用し、リファクタリング中に不適切なプロジェクトに伝播しました)。このフラグは、メッセージ マップ項目の定義を変更するため、MFC と互換性がありません。

長い話: スペースを節約するために、Microsoft は、クラスが単一継承、複数継承、または仮想継承のいずれを使用しているかに応じて、メンバーへのポインターを異なる方法で表現することを決定しました。理論的には問題ないように見えますが、実際には次の場合に問題があります。

  • 不完全な型のメンバーへのポインターが宣言されています (これは C++ では有効です)。

次の場合にも問題が発生すると思われます。

  • より複雑なポインターを持つクラスのメンバーへのポインターは、より単純なポインターを持つ基本クラスのメンバーへのポインターにキャストする必要があります。

ドキュメントにはそのケースについては言及されていませんが、それは明らかです。ちなみに、それはまさにMFCが行うことです。

仕様 (ISO/IEC 14882-2011) ではstatic_cast、基本が仮想的に継承されていない場合にのみ基本のメンバーへのポインターが必要ですが、Microsoft コンパイラでは、基本クラスが線形継承のみを持ち、サブクラスが複数の継承を持つ場合でも機能しません。ベースは非ファーストです。まあ、コンパイラがすでに非準拠であることは誰もが知っています。

于 2013-03-05T11:03:21.330 に答える