本ページは公開が終了した情報の複製であり、掲載時点での情報です。本ページに記載されている内容について各所に問い合わせることはご遠慮下さい。
サポート技術情報

[VC10]MFC200.DLLを使うプログラムのメッセージボックスの背景色が白くなる

文書番号: 401996

最終更新日: 2003/11/12


この資料は以下の製品について記述したものです。


概要

この資料は MFC200.DLL を使うプログラムのメッセージ ボックスの背景色が白くなる 現象について説明したものです。

詳細

Visual C++ 1.0 の MFC200.DLL を使用するプログラムを 2 つ同時に実行すると、
2 つ目以降のプログラムで表示するダイアログ ボックスやメッセージ ボックスの
背景色が白色になります。

原因

Microsoft Foundation Class ライブラリ (以下 MFC) は WH_CBT 用にフック関数を設定 します。この関数により MFC のプロシージャは、ダイアログ ボックスやメッセージ ボックスが表示されるタイミングを知ることができます。MFC は、このフック関数を それらの背景色ブラシの設定に使用します。MFC は、このフック関数を設定するとき 元のフック関数のアドレス (SetWindowsHookEx の戻り値) を保存しています。この元の フック関数のアドレスは各タスクごとに保存しておく必要があります。
  MFC 2.x のソースコードの抜粋 (appgray.cpp)
      // Win31 supports CBT window create hook
      if (_afxHHookOldCbtFilter == NULL)
          _afxHHookOldCbtFilter = SetWindowsHookEx(WH_CBT,
              (HOOKPROC)_AfxCbtFilterHook, _AfxGetHookHandle(),
              ::GetCurrentTask());
_afxHHookOldCbtFilter に MFC 2.x がチェインする (MFC 2.x 独自のフック関数の終了 後に実行する) ために元のフック関数のアドレスを保存しています。MFC 2.0 ではこの _afxHHookOldCbtFilter を初期値 NULL のグローバル変数として定義しており、
MFC200.DLL では、この変数は 1 つしか存在しません。
MFC200.DLL を使用する最初のプログラムの実行時、_afxHHookOldCbtFilter は元の
フック関数のアドレスを得ます。次に実行される (MFC200.DLL を使用する) プログラムも同じ変数を参照してしまいます。 _afxHHookOldCbtFilter が NULL の場合のみフック関数をセットしているため、
2 つ目以降のプログラムは背景色をセットするフック関数を設定できません。

対処方法

MFC 2.0 ではタスクごとにフック関数を定義することで回避できます。
以下にその手順を説明します。
  1. 以下の定義を CWinApp の派生クラスが定義されている .CPP ファイルに追加。
         HHOOK _afxHHookOldCbtFilter=NULL;
         LRESULT CALLBACK EXPORT _afxCbtFilterHook(int,WPARAM,LPARAM);
         LRESULT CALLBACK EXPORT _afxGrayBackgroundWndProc(HWND,UINT,WPARAM,LPARAM);
         HBRUSH afxDlgBkBrush;
         COLORREF afxDlgTextClr;
         LRESULT (CALLBACK EXPORT *lpfnDlgWndProc)(HWND,UINT,WPARAM,LPARAM);
    
  2. CWinApp 派生クラスの InitInstance 関数に以下のコードを追加。
         BOOL  ProjectApp::InitInstance( )
         {
             ... 他の初期化処理 ...
             if (lpfnDlgWndProc == NULL) // only set once
             {
                 // get info about standard dialog wnd proc
                 WNDCLASS wndcls;
                 VERIFY(::GetClassInfo(NULL, WC_DIALOG, &wndcls));
                 lpfnDlgWndProc = wndcls.lpfnWndProc;
             }
             afxDlgBkBrush=(HBRUSH)::GetStockObject(LTGRAY_BRUSH);
             _afxHHookOldCbtFilter = SetWindowsHookEx(WH_CBT,
                     (HOOKPROC)_afxCbtFilterHook, AfxGetInstanceHandle(),
                     ::GetCurrentTask());
         }
    
  3. 以下の関数を同じファイルに追加。
         LRESULT CALLBACK EXPORT
         _AfxGrayBackgroundWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
         {
             if (afxDlgBkBrush != NULL &&
                 nMsg == WM_CTLCOLOR &&
                 CWnd::GrayCtlColor((HDC)wParam, (HWND)LOWORD(lParam),
                     (UINT)HIWORD(lParam), afxDlgBkBrush, afxDlgTextClr))
             {
                 return (LRESULT)(WORD)afxDlgBkBrush;
             }
         #ifdef STRICT
             return CallWindowProc(lpfnDlgWndProc, hWnd, nMsg, wParam, lParam);
         #else
             return CallWindowProc((FARPROC)lpfnDlgWndProc, hWnd,nMsg,wParam,lParam);
         #endif
         }
         LRESULT CALLBACK EXPORT _AfxCbtFilterHook(int code, WPARAM wParam,
                                                                     LPARAM lParam)
             // WH_CBT 用フィルタ関数
         {
             static HWND hWndHookParentDlg = NULL;
             if (code == HCBT_CREATEWND)
             {
                 ASSERT(lParam != NULL);
                 LPCREATESTRUCT lpcs = ((LPCBT_CREATEWND)lParam)->lpcs;
                 ASSERT(lpcs != NULL);
                 if (lpcs->lpszClass == WC_DIALOG)
                 {
                     hWndHookParentDlg = (HWND)wParam;       // hook it
                 }
                 else if (hWndHookParentDlg != NULL)
                 {
                         // first control in a dialog dynamically subclass the parent
                         // is still a WC_DIALOG
                     if ((WNDPROC)GetWindowLong(hWndHookParentDlg,
                         GWL_WNDPROC) == lpfnDlgWndProc)
                     {
                         (WNDPROC)SetWindowLong(hWndHookParentDlg,
                               GWL_WNDPROC, (DWORD)_AfxGrayBackgroundWndProc);
                     }
                     hWndHookParentDlg = NULL;
                 }
             }
             // just call default handler and return the result
             return CallNextHookEx(_afxHHookOldCbtFilter, code, wParam, lParam);
         }
    

詳細

Visual C++ 1.5 の MFC 2.5 では、修正されています。

詳細

  • Visual C++ は、米国 Microsoft Corporation の登録商標です。

Keywords: KBBUG KB401996
Technology: kbAudDeveloper kbVCsearch

inserted by FC2 system