MFC ActiveX コントロール : Windows コントロールのサブクラス化

この記事では、一般的な Windows コントロールをサブクラス化して ActiveX コントロールを作成するプロセスについて説明します。 既存の Windows コントロールをサブクラス化することは、ActiveX コントロールを開発するための簡単な方法です。 新しいコントロールは、描画やマウス クリックに対する応答など、サブクラス化された Windows コントロールの機能を備えています。 MFC ActiveX コントロールのサンプル BUTTON は、Windows コントロールをサブクラス化する例です。

重要

ActiveX は、新しい開発には使用すべきではないレガシ テクノロジです。 ActiveX に取って代わる最新のテクノロジの詳細については、「ActiveX コントロール」を参照してください。

Windows コントロールをサブクラス化するには、次のタスクを実行します。

IsSubclassedControl と PreCreateWindow のオーバーライド

PreCreateWindowIsSubclassedControl をオーバーライドするには、コントロール クラス宣言の protected セクションに次のコード行を追加します。

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
BOOL IsSubclassedControl();

コントロール実装ファイル (.CPP) で、次のコード行を追加して、オーバーライドされる 2 つの関数を実装します。

// CMyAxSubCtrl::PreCreateWindow - Modify parameters for CreateWindowEx

BOOL CMyAxSubCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
   cs.lpszClass = _T("BUTTON");
   return COleControl::PreCreateWindow(cs);
}

// CMyAxSubCtrl::IsSubclassedControl - This is a subclassed control

BOOL CMyAxSubCtrl::IsSubclassedControl()
{
   return TRUE;
}

この例では、Windows ボタン コントロールが PreCreateWindow で指定されていることに注意してください。 ただし、すべての標準 Windows コントロールはサブクラス化できます。 標準の Windows コントロールの詳細については、コントロールに関するページを参照してください。

Windows コントロールをサブクラス化する場合は、コントロールのウィンドウを作成するときに使用する特定のウィンドウ スタイル (WS_) または拡張ウィンドウ スタイル (WS_EX_) フラグを指定することができます。 cs.style および cs.dwExStyle 構造体フィールドを変更することにより、PreCreateWindow メンバー関数でこれらのパラメーターの値を設定できます。 これらのフィールドに対する変更は、クラス COleControl によって設定される既定のフラグを保持するために、OR 操作を使用して行う必要があります。 たとえば、コントロールが BUTTON コントロールをサブクラス化している場合、コントロールがチェック ボックスとして表示されるようにするには、次のコード行を CSampleCtrl::PreCreateWindow の実装の return ステートメントの前に挿入します。

cs.style |= BS_CHECKBOX;

この操作では、クラス COleControl の既定のスタイル フラグ (WS_CHILD) をそのままにして、BS_CHECKBOX スタイル フラグを追加します。

OnDraw メンバー関数の変更

サブクラス化されたコントロールの外観を対応する Windows コントロールと同じに保つには、次の例のように、コントロールの OnDraw メンバー関数に DoSuperclassPaint メンバー関数の呼び出しのみを含める必要があります。

void CMyAxSubCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /*rcInvalid*/)
{
   if (!pdc)
      return;

   DoSuperclassPaint(pdc, rcBounds);
}

COleControl によって実装される DoSuperclassPaint メンバー関数は、Windows コントロールのウィンドウ プロシージャを使用して、指定されたデバイス コンテキストの四角形領域内にコントロールを描画します。 これにより、アクティブでない場合でもコントロールが表示されるようになります。

Note

DoSuperclassPaint メンバー関数は、デバイス コンテキストを WM_PAINT メッセージの wParam として渡すことができるコントロールの種類でのみ機能します。 これには、SCROLLBAR や BUTTON などの標準の Windows コントロールの一部と、すべての共通コントロールが含まれます。 この動作をサポートしないコントロールに対しては、非アクティブなコントロールを適切に表示するための独自のコードを用意する必要があります。

返送されるウィンドウ メッセージの処理

Windows コントロールは、通常、特定のウィンドウ メッセージを親ウィンドウに送信します。 WM_COMMAND など、これらのメッセージの一部は、ユーザーによるアクションに関する通知を提供します。 WM_CTLCOLOR などの他のものは、親ウィンドウから情報を取得するために使用されます。 ActiveX コントロールでは、通常、他の方法で親ウィンドウと通信します。 通知は、イベントの発生 (イベント通知の送信) によって伝達されます。コントロール コンテナーに関する情報は、コンテナーのアンビエント プロパティにアクセスすることによって取得されます。 これらの通信方法が存在するため、コントロールによって送信されるウィンドウ メッセージを ActiveX コントロール コンテナーで処理することは想定されていません。

サブクラス化された Windows コントロールから送信されるウィンドウ メッセージをコンテナーが受信するのを防ぐために、コントロールの親として機能する追加のウィンドウが COleControl によって作成されます。 "リフレクター" と呼ばれるこの追加のウィンドウは、Windows コントロールをサブクラス化し、サイズと位置がコントロール ウィンドウと同じ ActiveX コントロールに対してのみ作成されます。 リフレクター ウィンドウは、特定のウィンドウ メッセージをインターセプトし、それらをコントロールに送り返します。 その後、コントロールは、ウィンドウ プロシージャで、ActiveX コントロールに適したアクション (イベントの発生など) を実行することで、これらの返送されるメッセージを処理できます。 インターセプトされたウィンドウ メッセージとそれに対応する返送されるメッセージの一覧については、「返送されるウィンドウ メッセージの ID」を参照してください。

ActiveX コントロール コンテナーは、メッセージ返送をそれ自体で実行して、COleControl でリフレクター ウィンドウを作成する必要性をなくし、サブクラス化された Windows コントロールの実行時のオーバーヘッドを小さくするように設計することができます。 COleControl では、値が TRUE の MessageReflect アンビエント プロパティがあるかどうかを調べることによって、コンテナーがこの機能をサポートしているかどうかを検出します。

返送されるウィンドウ メッセージを処理するには、コントロール メッセージ マップにエントリを追加し、ハンドラー関数を実装します。 返送されるメッセージは Windows で定義されている標準のメッセージ セットの一部ではないため、クラス ビューではそのようなメッセージ ハンドラーの追加はサポートされません。 ただし、ハンドラーを手動で追加するのは難しくありません。

返送されるウィンドウ メッセージのメッセージ ハンドラーを手動で追加するには、次の操作を行います。

  • コントロール クラスの .H ファイルで、ハンドラー関数を宣言します。 この関数では、戻り値は LRESULT 型で、2 つのパラメーターはそれぞれ WPARAM 型と LPARAM 型である必要があります。 次に例を示します。

    class CMyAxSubCtrl : public COleControl
    {
    
    protected:
       LRESULT OnOcmCommand(WPARAM wParam, LPARAM lParam);
    };
    
  • コントロール クラスの .CPP ファイルで、メッセージ マップに ON_MESSAGE エントリを追加します。 このエントリのパラメーターは、メッセージ識別子とハンドラー関数の名前である必要があります。 次に例を示します。

    BEGIN_MESSAGE_MAP(CMyAxSubCtrl, COleControl)
       ON_MESSAGE(OCM_COMMAND, &CMyAxSubCtrl::OnOcmCommand)
    END_MESSAGE_MAP()
    
  • 再び .CPP ファイルで、返送されるメッセージを処理するための OnOcmCommand メンバー関数を実装します。 wParam および lParam パラメーターは、元のウィンドウ メッセージのパラメーターと同じです。

返送されるメッセージの処理方法の例については、MFC ActiveX コントロールのサンプル BUTTON を参照してください。 これは、BN_CLICKED 通知コードを検出し、Click イベントを発生 (送信) することで応答する OnOcmCommand ハンドラーを示しています。

関連項目

MFC ActiveX コントロール