假设我需要在C ++ Builder cpp文件中创建一个Windows消息处理程序。
我会为WM_SIZE
写一个像这样的处理程序:
h file:
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_SIZE, TWMSize, OnWMSize)
END_MESSAGE_MAP(TControl)
void __fastcall OnWMSize(TWMSize &msg);
cpp文件:
void __fastcall TForm1::OnWMSize(TWMSize &msg)
{
if (msg.SizeType == SIZE_MAXIMIZED)
Caption = "Maximized";
// This is a Delphi call and won't work in C++:
// inherited;
// Cpp call. Won't compile due to method visibility (private)
// TForm::WMSize(msg);
// Cpp call. Compiles but doesn't get expected behavior
DefaultHandler((void*)&msg);
}
如示例所示,使用Delphi非常简单,只需调用inherited
。
但是使用C ++,如何在C ++ Builder中调用基类? WMSize
方法在TScrollingWinControl
中声明为私有。
在此示例中,不调用基类会破坏Anchors
功能。使用DefaultHandler
也无法解决问题。
我错过了一些明显的东西吗?
答案 0 :(得分:1)
首先,您将错误的类类型传递给END_MESSAGE_MAP()
。您需要指定直接父类,在本例中为TForm
,而不是TControl
:
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_SIZE, TWMSize, OnWMSize)
END_MESSAGE_MAP(TForm) // <-- here
现在,据说,MESSAGE_MAP
只是一种覆盖虚拟Dispatch()
方法的奇特方式:
#define BEGIN_MESSAGE_MAP virtual void __fastcall Dispatch(void *Message) \
{ \
switch (((PMessage)Message)->Msg) \
{
#define VCL_MESSAGE_HANDLER(msg,type,meth) \
case msg: \
meth(*((type *)Message)); \
break;
// NOTE: ATL defines a MESSAGE_HANDLER macro which conflicts with VCL's macro. The
// VCL macro has been renamed to VCL_MESSAGE_HANDLER. If you are not using ATL,
// MESSAGE_HANDLER is defined as in previous versions of BCB.
//
#if !defined(USING_ATL) && !defined(USING_ATLVCL) && !defined(INC_ATL_HEADERS)
#define MESSAGE_HANDLER VCL_MESSAGE_HANDLER
#endif // ATL_COMPAT
#define END_MESSAGE_MAP(base) default: \
base::Dispatch(Message); \
break; \
} \
}
因此,您的MESSAGE_MAP
解析为以下代码逻辑:
virtual void __fastcall Dispatch(void *Message)
{
switch (((PMessage)Message)->Msg)
{
case WM_SIZE:
OnWMSize(*((TWMSize *)Message));
break;
default:
TForm::Dispatch(Message);
break;
}
}
如您所见,END_MESSAGE_MAP()
只是将未处理的消息传递给基类TForm::Dispatch()
方法。您必须在消息处理程序中执行相同的操作,例如:
void __fastcall TForm1::OnWMSize(TWMSize &msg)
{
if (msg.SizeType == SIZE_MAXIMIZED)
Caption = "Maximized";
TForm::Dispatch(&msg);
}