在Windows程序设计中,经常需要使用::SendMessage和::PostMessage函数来发送消息。但是,这些函数在传递消息参数时并不保证类型安全。必须将参数强制转换为WPARAM或LPARAM数据类型,然后在处理函数中再转换回所需的数据类型。这在传递数值时就已经很糟糕了,而在传递指针时更是如此。下面定义的宏允许在MFC应用程序中简单实现类型安全的消息传递。此外,这些宏还提供了基于HWND的消息传递,使用方法调用语义。
将以下宏定义放入代码中:
#define TYPESAFE_MESSAGE(NAME, MSG, RESULT, ARG1, ARG2) \
const UINT MSG__##NAME((MSG)); \
inline RESULT NAME(\
const HWND hwnd, ARG1 a, ARG2 b) { \
return (RESULT)(::SendMessage(hwnd, (MSG), WPARAM(a), LPARAM(b))); } \
inline BOOL post__##NAME(\
const HWND hwnd, ARG1 a, ARG2 b) { \
return ::PostMessage(hwnd, (MSG), WPARAM(a), LPARAM(b)); }
宏定义用于定义消息处理程序:
#define TYPESAFE_MESSAGE_HANDLER(NAME, RESULT, ARG1, ARG2) \
virtual RESULT NAME(ARG1, ARG2); \
afx_msg LRESULT ON__##NAME(WPARAM a, LPARAM b) { \
return LRESULT(NAME((ARG1)a, (ARG2)b)); }
宏定义用于定义消息映射条目:
#define TYPESAFE_MAPENTRY(NAME) ON_MESSAGE(MSG__##NAME, ON__##NAME)
宏的使用方式如下:
创建一个头文件来包含全局消息描述(例如:app_messages.h)。使用TYPESAFE_MESSAGE宏在全局作用域定义消息。
使用TYPESAFE_MESSAGE_HANDLER宏在CWnd派生类定义中添加消息处理程序。
使用TYPESAFE_MAPENTRY宏在MFCMESSAGE_MAP中添加条目。
编写由TYPESAFE_MESSAGE_HANDLER宏定义的消息处理程序方法的主体。
假设想要创建一个名为on_foo的消息,消息代码为WM_APP+200。此外,希望on_foo接收一个const int和一个const CWnd*作为参数,并希望on_foo返回一个float。最后,希望类MyClass有一个on_foo的处理程序。
在文件app_messages.h中定义:
TYPESAFE_MESSAGE(on_foo, WM_APP+200, float, const int, const CWnd*)
在文件MyClass.h中定义:
class MyClass : public CWnd {
...
TYPESAFE_MESSAGE_HANDLER(on_foo, float, const int, const CWnd*)
...
};
在文件MyClass.cpp中定义:
BEGIN_MESSAGE_MAP(MyClass, CWnd)
...
TYPESAFE_MAPENTRY(on_foo)
END_MESSAGE_MAP()
float MyClass::on_foo(const int a, const CWnd* b) {
...
}
现在,可以向任何MyClass窗口发送on_foo消息,并使用以下代码调用MyClass::on_foo方法:
float x = on_foo(hwnd, a, b); // 其中hwnd是指向MyClass窗口的窗口句柄
或者,可以使用以下代码发布on_foo消息:
BOOL b = post_on_foo(hwnd, a, b);
注意,在这两种情况下,都在使用方法调用语义进行消息传递。
在上面的例子中,TYPESAFE_MESSAGE宏在全局作用域创建了以下代码:
const UINT MSG__on_foo(WM_APP+200);
inline float on_foo(const HWND hwnd, const int a, const CWnd* b) {
return float(::SendMessage(hwnd, WM_APP+200, WPARAM(a), LPARAM(b)));
}
inline BOOL post_on_foo(const HWND hwnd, const int a, const CWnd* b) {
return ::PostMessage(hwnd, WM_APP+200, WPARAM(a), LPARAM(b));
}
TYPESAFE_MESSAGE_HANDLER宏在MyClass头文件中生成了以下代码:
virtual float on_foo(const int, const CWnd*);
afx_msg LRESULT ON__on_foo(WPARAM a, LPARAM b) {
return LRESULT(on_foo(const int a, const CWnd* b));
}
void on_foo__compile_test() const {
float x = ::on_foo((HWND)0, (const int)0, (const CWnd*)0);
}
TYPESAFE_MAPENTRY宏在MyClass的MFC消息映射中生成了以下代码:
ON_MESSAGE(MSG__on_foo, ON__on_foo)
在MyClass中,ON__on_foo MFC消息处理程序接收on_foo消息,将参数转换为正确的数据类型,并调用on_foo方法。