SendMessageと非標準メッセージ

Windowsはメッセージのやりとりで様々な処理が行われています。 このメッセージを利用すれば通常呼び出せない関数を間接的に呼び出したりできます。

SendMessage()関数

SendMessage()関数はメッセージを送ります。
そのメッセージを受け取るのがCWnd(ウインドウですなぁ)で、 ウィンドウは受け取ったらなにをするかというと、 メッセージに対応するイベントを呼び出します。

たとえば、

SendMessage(WM_LBUTTONDOWN, hoge1, hoge2)

とするとマウスの左ボタンをクリックしたイベント(OnLButtonDown)を呼び出します。

SendMessage()関数
LRESULT SendMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 );
引数説明
message 送信するメッセージID
wParam メッセージに依存する付加情報を指定します。
lParam メッセージに依存する付加情報を指定します。
wParamやlParamはキャストする事で値の作成が可能です。
たとえば
(LPARAM)"test"
(WPARAM)this
と行った具合です(thisは試していないけど)

SendMessage()関数は送られたメッセージIDが処理されるまで待ちます。
このほかにPostMessage()関数というものもあります。こちらは送られたメッセージが 処理される前に戻ってきます。

メッセージIDの定義

メッセージIDはユーザーが定義することも可能です。

まず#defineでメッセージIDを定義します。
メッセージIDはWM_USER(0x0400)〜0x7FFFまでの範囲で設定することが可能です

#define USER_MESSAGE (WM_USER+0x1000)

後ろの(WM_USER+0x1000)はメッセージIDの番号を定義しています。
これらの独自のメッセージIDは一つのヘッダファイルにまとめて定義しておくと、 管理が楽にできます。

で、このメッセージIDに対応した関数を作成し呼び出せるようにします。
ヘッダーファイルに
    //{{AFX_MSG(CTLTree)
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
となっている部分があります。
ここにまず、関数のプロトタイプを宣言します。
注意しなければならないことは

    //{{AFX_MSG(CTLTree)〜//}}AFX_MSG

の中に宣言をしないことです。

この//{{AFX_MSG(CTLTree)〜//}}AFX_MSGの間はClassWizardが参照する場所で、 ClassWizardが理解できないものは削除されてしまいます。
なので、DECLARE_MESSAGE_MAP()の前にプロトタイプを宣言します
    //{{AFX_MSG(CTLTree)
    //}}AFX_MSG
    afx_msg void OnHogeHogeEvent();
    DECLARE_MESSAGE_MAP()
これで関数の宣言は完了。今度はソースファイル(.cpp/.c)に関数の実体と、 メッセージIDと関数の関連づけを行います。

まず、関連づけから行きましょう。
ソースファイルに
    BEGIN_MESSAGE_MAP(CHoge, CHoge)
        //{{AFX_MSG_MAP(CHoge)
        //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
となっている場所があります。(CHogeはクラスの名前で変わる)
たいていはファイルの先頭の方にあります。
こちらも
//{{AFX_MSG_MAP(CTLTree)〜//}}AFX_MSG_MAP
の間に宣言してはいけません。
END_MESSAGE_MAP()の前に宣言しましょう。
    BEGIN_MESSAGE_MAP(CHoge, CHoge)
        //{{AFX_MSG_MAP(CHoge)
        //}}AFX_MSG_MAP
    ON_MESSAGE(USER_MESSAGE,OnHogeHogeEvent)
    END_MESSAGE_MAP()
ON_MESSAGEはユーザー定義用のマクロで必須です。
ON_MESSAGEマクロ
ON_MESSAGE( message, memberFxn )
引数説明
message メッセージID
memberFxn メッセージがマップされるメッセージ処理関数名
ここまでできたら関数を作成すれば良いです。