この記事では、一般的な Windows コントロールをサブクラス化して ActiveX コントロールを作成するプロセスについて説明します。 既存の Windows コントロールのサブクラス化は、ActiveX コントロールをすばやく開発する方法です。 新しいコントロールには、描画やマウスクリックへの応答など、サブクラス化された Windows コントロールの機能があります。 MFC ActiveX コントロールのサンプル BUTTON は、Windows コントロールをサブクラス化する例です。
Von Bedeutung
ActiveX は、新しい開発には使用すべきではないレガシ テクノロジです。 ActiveX に代わる最新のテクノロジの詳細については、「 ActiveX コントロール」を参照してください。
Windows コントロールをサブクラス化するには、次のタスクを実行します。
COleControl の IsSubclassedControl および PreCreateWindow メンバー関数をオーバーライドする
コントロールに反映された ActiveX コントロール メッセージ (OCM) を処理する
注
この作業の多くは、[コントロールの設定] ページの [親ウィンドウ クラスの選択] ドロップダウン リストを使用してサブクラス化するコントロールを選択した場合、ActiveX コントロール ウィザードによって行われます。
IsSubclassedControl と PreCreateWindow のオーバーライド
PreCreateWindow
とIsSubclassedControl
をオーバーライドするには、コントロール クラス宣言の 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 コントロールをサブクラス化していて、コントロールをチェック ボックスとして表示する場合は、return ステートメントの前に、 CSampleCtrl::PreCreateWindow
の実装に次のコード行を挿入します。
cs.style |= BS_CHECKBOX;
この操作では、クラスの既定のスタイル フラグ (WS_CHILD) をそのまま残しながら、BS_CHECKBOX スタイル フラグ COleControl
追加します。
OnDraw メンバー関数の変更
サブクラス化されたコントロールの外観を、対応する Windows コントロールと同じにする場合、コントロールの OnDraw
メンバー関数には、次の例のように、 DoSuperclassPaint
メンバー関数の呼び出しのみを含める必要があります。
void CMyAxSubCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /*rcInvalid*/)
{
if (!pdc)
return;
DoSuperclassPaint(pdc, rcBounds);
}
COleControl
によって実装される DoSuperclassPaint
メンバー関数は、Windows コントロールのウィンドウ プロシージャを使用して、指定されたデバイス コンテキスト内の境界四角形内にコントロールを描画します。 これにより、アクティブでない場合でもコントロールが表示されます。
注
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
ハンドラーを示します。