类型安全的Windows消息传递

在Windows程序设计中,经常需要使用::SendMessage::PostMessage函数来发送消息。但是,这些函数在传递消息参数时并不保证类型安全。必须将参数强制转换为WPARAMLPARAM数据类型,然后在处理函数中再转换回所需的数据类型。这在传递数值时就已经很糟糕了,而在传递指针时更是如此。下面定义的宏允许在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宏在MyClassMFC消息映射中生成了以下代码:

ON_MESSAGE(MSG__on_foo, ON__on_foo)

MyClass中,ON__on_foo MFC消息处理程序接收on_foo消息,将参数转换为正确的数据类型,并调用on_foo方法。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485