在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
方法。