ツールバーを使用する MFC アプリケーションで起動に失敗する場合がある

適用対象: Visual Studio Professional 2010Visual Studio Premium 2010Visual Studio Ultimate 2010

現象


MFC のツールバー (CMFCToolBar クラス) を使用するアプリケーションで、アプリケーションの起動時に異常終了する場合があります。
ツールバーの状態と実行時の内部処理のタイミングに依存して現象が発生するため、同じ環境で同じアプリケーションを実行しても、正常に実行できる場合と異常終了する場合があります。

原因


Visual C++ 2008 SP1 以降の MFC アプリケーション (CWinAppEx クラスを使用) では、アプリケーションの起動時に、ツールバーやドッキング コントロールの状態を前回アプリケーション実行時の状態に復元する機能が提供されています。前回実行時の状態はレジストリに保存されています。
このレジストリからの状態復元処理において、アプリケーション起動時の初期状態のツールバー メニュー ボタン (CMFCToolBarMenuButton) オブジェクトの状態と、レジストリから読み込んだ前回の状態との比較が行われますが、特定の条件下において、レジストリから読み込んだ情報から生成されたオブジェクトが必要な情報を持たない状況が発生します。

具体的には、CMFCToolBarMenuButton クラスの一部の情報を持たず、基底クラスの CMFCToolBarButton クラスの情報のみを持っているため、オブジェクトのサイズとしても必要な領域が確保されていない状態となります。
その結果、初期状態と前回実行時の CMFCToolBarMenuButton オブジェクトの比較処理において、上記の不足分の領域に対応する不正なアドレスへの参照が行われ、アクセス違反によるアプリケーションの異常終了が発生します。

回避策


本現象は以下のいずれかの方法で回避することが可能です。
いずれの方法でも、前回実行時の状態への復元は行われなくなります。


・問題発生時に、前回アプリケーション実行時のコントロールの状態を保存した以下のレジストリ キーを削除します。
レジストリ上に保存された前回実行時の状態を削除することで、問題が生じる比較処理が行われないようにします。
レジストリ操作については不適切な操作を行わないように十分留意する必要がありますが、本キーの削除は本問題に対する適切な対処方法となり、アプリケーションの動作自体や他のアプリケーションに対する影響はありません。
HKEY_USERS\<ユーザーの SID>\Software\アプリケーション ウィザードで生成されたローカル アプリケーション\<アプリケーション名>

・CMFCToolBar クラスの派生クラスを作成し、CMFCToolBar::LoadState メンバ関数をオーバーライドします。
オーバーライドした関数では、CMFCToolBar::LoadState メンバ関数の実装をコピーし、LoadLastOriginalState 関数の呼び出しのみコメント アウトします。これにより、レジストリに保存された前回実行時の状態の復元動作をスキップすることができます。

状況


マイクロソフトでは、この問題をこの資料の対象製品として記載されているマイクロソフト製品の問題として認識しています。