入門

なんか、昨日 id:ahiruさんにActiveXについて教えてくれと言われたので、教えていくうちに、MFCについてよく知らないことが分かったので、思い出しながら説明した。Document,Viewは学習する場合は邪魔者でしかないんだよなぁ。
すっかり忘れていたのだけど、せっかくだからここにまとめて書いておく。


MFCの最小コード

#include 			// MFC用のインクルードファイル
#define EV_BUTTON 100		// イベント用ID

// ウィンドウ定義クラス
class CMainFrame : public CFrameWnd
{
private:
	CStatic theStatic;	//ラベル
	CButton theButton;	//ボタン
public:

	// ③ウィンドウのコンストラクタ
	CMainFrame() {
		// ウィンドウを作成
		Create(NULL, "aa", WS_OVERLAPPEDWINDOW,
			CRect(20, 20, 20 + 400, 20 + 400));
		// ラベルを作成して、thisの上に貼り付ける。
		theStatic.Create("moji", WS_VISIBLE,
			CRect(30, 30, 30 + 150, 30 + 200), this);
		// ボタンを作成して、thisの上に貼り付ける。
		// ボタンを押したときはEV_BUTTONイベントが発生する。
		theButton.Create("moji", WS_VISIBLE,
			CRect(200, 30, 200 + 150, 30 + 200), this, EV_BUTTON);
	}

	// theButtonを押したときに呼び出される。
	void OnClickTheButton() {
		OutputDebugString("test\n");
	}

	// メッセージ用マクロ
	DECLARE_MESSAGE_MAP()
};

//メッセージ登録
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
	ON_COMMAND(EV_BUTTON, OnClickTheButton)// EV_BUTTONメッセージを受けたら、OnClickButtonを呼び出す。
END_MESSAGE_MAP()

class CAaaApp : public CWinApp
{
public:
	// ②最初にここが動く
	BOOL InitInstance() {
		m_pMainWnd = new CMainFrame();	// ウィンドウ作成③へ
		m_pMainWnd->ShowWindow(SW_SHOW);// ウィンドウ表示
		m_pMainWnd->UpdateWindow();		// ウィンドウ再描画要求
		return TRUE;
		// この後メッセージループに入る。
	}

	// メッセージ用マクロ
	DECLARE_MESSAGE_MAP()
};

//メッセージ登録
BEGIN_MESSAGE_MAP(CAaaApp, CWinApp)
END_MESSAGE_MAP()

// ①クラスが生成される。
CAaaApp theApp;

ビルド方法


これをaaa.cppとして保存しておいて、MFCのプロジェクトとして作った雛型から全部ファイルなくした後、プリコンパイルヘッダも使わないようにしてあげて、ビルドする。


説明


①このプログラムはまず、CAaaApp theApp;が生成される。theAppはアプリケーションにひとつだけあればよい。CAaaAppはCWinAppを継承している。
②CWinAppは生成されると、InitInstance関数を呼ばれる。InitInstanceではアプリケーションの初期化を行う。最小のものを作る場合は、ウィンドウクラスを作って、表示して、再描画要求を出すだけだ。
③ウィンドウクラスを作ると、ウィンドウクラスのコンストラクタが呼び出される。ここで、まず自分自身のウィンドウを作り、貼り付けるコントロールの生成を行う。


コントロールの配置
コントロールは、CStatic(ラベル)、CButton(ボタン)、CEdit(テキストフィールド)、CListBox(リストボックス)などのクラスを使い配置する。CStaticを配置する場合の手順は、まず、CMainFrameWndにメンバ変数として登録し、次にコンストラクタでCreateメソッドを使って、配置する。

private:
	CStatic theStatic;	//ラベル
...
	CMainFrame() {
...
		// ラベルを作成して、thisの上に貼り付ける。
		theStatic.Create("moji", WS_VISIBLE,
			CRect(30, 30, 30 + 150, 30 + 200), this);
...
	}

イベントの仕組み
MFCのイベントはDECLARE_MESSAGE_MAP、BEGIN_MESSAGE_MAP、ON_COMMAND、END_MESSAGE_MAPといったマクロを使って簡単に書けるような仕組みを用意している。登録方法は以下のとおり。
イベントのID(この場合#define EV_BUTTON 100)を定義して、それをBEGIN_MESSAGE_MAPから始まるイベント登録部分に、

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
	ON_COMMAND(EV_BUTTON, OnClickTheButton)
END_MESSAGE_MAP()

のように登録する。すると、EV_BUTTONメッセージを受けたときに、OnClickTheButtonメソッドが呼び出されるようになる。BEGIN_MESSAGE_MAPの第一引数がクラス名で、第二引数が継承元のクラス名である。


この例では、メソッドは全てインラインで書いたが実際には分けたほうが良い。.hと.cppも分けたほうが良い。プリコンパイルヘッダも使おう。また、MFCの暮らすウィーザード用のコードも省いているので、実際にウィーザードが作ってくれたソースで書き換えないでと書いてあるところは残して作業ればクラスウィーザードを利用でき快適である。WS_VISIBLEなどの属性については、ダイアログで作ったもののリソースを眺めてコピペすると楽である。
この仕組みを理解した上で、ダイアログベースのウィンドウを作り、それをコントロールと同じように、ウィンドウ上に貼り付けてあげれば、コンポーネント的に使えることが分かると思う。


それを踏まえ、ActiveX化すればそんなに難しくないことが分かるはずである。