WTLの詳細分析-WTLフレームワークウィンドウの分析(4)

4005 ワード

superclassは、新しいウィンドウクラスを生成する方法です.既存のウィンドウクラスに依存して、別のウィンドウクラスをクローン化することを中心としています.クローンされたクラスは、ボタンやドロップダウンボックス制御など、Windowsで定義されたウィンドウクラスであってもよい.普通のクラスでもいいです.クローンされたウィンドウクラスは、クローンされたクラス(ベースクラス)のウィンドウメッセージ処理関数を使用します.
クローンクラスには、独自のウィンドウメッセージ処理関数を使用するか、ベースクラスのウィンドウ処理関数を使用することができます.
superclassは、ウィンドウクラスを登録するときにウィンドウの動作を変更することに注意してください.すなわち、ベースクラスのウィンドウ関数または自分で定義したウィンドウ関数を指定します.これは後述するsubclassとは異なります.後者は,ウィンドウ作成後,ウィンドウ関数のアドレスを修正するなどして1つのウィンドウの挙動を変える.
例(MSDNより抜粋):
class CBeepButton: public CWindowImpl< CBeepButton >
{
public:
   DECLARE_WND_SUPERCLASS( _T("BeepButton"), _T("Button") )
   BEGIN_MSG_MAP( CBeepButton )
      MESSAGE_HANDLER( WM_LBUTTONDOWN, OnLButtonDown )
   END_MSG_MAP()
   LRESULT OnLButtonDown( UINT, WPARAM, LPARAM, BOOL& bHandled )
   {
      MessageBeep( MB_ICONASTERISK );
      bHandled = FALSE; // alternatively: DefWindowProc()
      return 0;
   }
}; // CBeepButton

このクラスはボタンを実現し、クリックすると音がします.
このクラスのメッセージマッピング処理WM_LUTTONDOWNメッセージ.その他のメッセージは、Windowsのデフォルトウィンドウ関数で処理されます.
メッセージマッピングの前に、DECLARE_というマクロがあります.WND_SUPERCLASS().その役割はBeepButtonがButtonのsuperclassであることを明らかにすることです.
このマクロを分析します.
#define DECLARE_WND_SUPERCLASS(WndClassName, OrigWndClassName) /
static CWndClassInfo& GetWndClassInfo() /
{ /
	static CWndClassInfo wc = /
	{ /
		{ sizeof(WNDCLASSEX), 0, StartWindowProc, /
		  0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, /
		OrigWndClassName, NULL, NULL, TRUE, 0, _T("") /
	}; /
	return wc; /
}

このマクロは静的関数GetWndClassInfo()を定義する.この関数は、ウィンドウクラス登録時に使用されるデータ構造CWndClassInfoを返します.構造の詳細は次のとおりです.
struct _ATL_WNDCLASSINFOA
{
	WNDCLASSEXA m_wc;
	LPCSTR m_lpszOrigName;
	WNDPROC pWndProc;
	LPCSTR m_lpszCursorID;
	BOOL m_bSystemCursor;
	ATOM m_atom;
	CHAR m_szAutoName[13];
	ATOM Register(WNDPROC* p)
	{
		return AtlModuleRegisterWndClassInfoA(&_Module, this, p);
	}
};
struct _ATL_WNDCLASSINFOW
{
 … …
	{
		return AtlModuleRegisterWndClassInfoW(&_Module, this, p);
	}
};
typedef _ATL_WNDCLASSINFOA CWndClassInfoA;
typedef _ATL_WNDCLASSINFOW CWndClassInfoW;
#ifdef UNICODE
#define CWndClassInfo CWndClassInfoW
#else
#define CWndClassInfo CWndClassInfoA
#endif

この構造は静的関数AtlModuleRegisterWndClassInfoA(&_Module,this,p)を呼び出した.この関数の用途は、ウィンドウクラスを登録することです.
WndClassNameがOrigWdClassNameのsuperclassであることを指定します.
subclass
subclassは一般的に採用されているウィンドウ機能を拡張する方法である.その大まかな原理は以下の通りである.
ウィンドウの作成が完了したら、ウィンドウのウィンドウ関数を新しいウィンドウメッセージ処理関数に置き換えます.この新しいウィンドウ関数は、処理する必要がある特定のメッセージを処理し、元のウィンドウ関数に処理を渡すことができます.
superclassとの違いに注意してください.
Superclassは1つのクラスを原版としてクローンを作成します.既存のウィンドウクラスを登録する場合は、ベースクラスウィンドウのウィンドウ関数を使用します.
subclassは、あるウィンドウが登録されて作成された後、そのウィンドウのウィンドウメッセージ関数のアドレスを変更することによって実現される.ウィンドウのインスタンスです.
MSDNからの例を見てみましょう
class CNoNumEdit: public CWindowImpl< CNoNumEdit >
{
   BEGIN_MSG_MAP( CNoNumEdit )
      MESSAGE_HANDLER( WM_CHAR, OnChar )
   END_MSG_MAP()
   LRESULT OnChar( UINT, WPARAM wParam, LPARAM, BOOL& bHandled )
   {
      TCHAR ch = wParam;
      if( _T('0') <= ch && ch <= _T('9') )
         MessageBeep( 0 );
      else
         bHandled = FALSE;
      return 0;
   }
};

ここでは、数値のみを受信する編集コントロールを定義します.すなわち、メッセージマッピングにより、特殊なメッセージ処理ロジックが定義される.
そして、CWindowImpltを使います.SubclassWindow()は、サブclassの編集コントロールを作成します.
class CMyDialog: public CDialogImpl
{
public:
   enum { IDD = IDD_DIALOG1 };
   BEGIN_MSG_MAP( CMyDialog )
      MESSAGE_HANDLER( WM_INITDIALOG, OnInitDialog )
   END_MSG_MAP()
   LRESULT OnInitDialog( UINT, WPARAM, LPARAM, BOOL& )
   {
      ed.SubclassWindow( GetDlgItem( IDC_EDIT1 ) ); 
      return 0;
   }

   CNoNumEdit ed;
};

上記のコードでは、ed.SubclassWindow(GetDlgItem(IDC_EDIT 1))文はIDC_EDIT 1という編集コントロールはsubclassを行います.この文は、実際には編集コントロールを置き換えたウィンドウ関数です.
SubClassWindows()の実装メカニズムは、ATLがウィンドウ関数をカプセル化するメカニズムと同様であるため、ATLがどのように実装されているかについては後述する.