BEGIN_MESSAGE_MAP导致C++Builder 10.1崩溃到桌面

BEGIN_MESSAGE_MAP caused C++ Builder 10.1 to crash to desktop

本文关键字:崩溃 桌面 C++Builder MESSAGE MAP 导致 BEGIN      更新时间:2023-10-16

我正在编写一个VCL组件TGIcon,以模拟windows桌面中的图标,它一直运行良好,直到我决定将MouseEnter和MouseLeave事件添加到组件中。我遵循了以下指南:Embarcadero Community

这是我的代码(标题(:

class PACKAGE TGIcon : public TGraphicControl
{
private:
AnsiString FCaption;
TPngImage *FIcon, *FDIcon;
TFont *FFont;
TNotifyEvent FOnMouseEnter;
TNotifyEvent FOnMouseLeave;
void __fastcall CMMouseEnter(TMessage &Message);
void __fastcall CMMouseLeave(TMessage &Message);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGIcon)
protected:
virtual void __fastcall Paint();
void __fastcall SetCaption(AnsiString value);
void __fastcall SetIcon(TPngImage *value);
void __fastcall SetFont(TFont *value);
public:
__fastcall TGIcon(TComponent* Owner);
__fastcall ~TGIcon();
void __fastcall MakeGray(void);
__published:
__property AnsiString Caption = {read=FCaption, write=SetCaption, nodefault};
__property TPngImage  *Icon   = {read=FIcon, write=SetIcon};
__property TFont      *Font   = {read=FFont, write=SetFont};
__property Parent;
__property Enabled;
__property OnClick;
__property TNotifyEvent OnMouseEnter = {read=FOnMouseEnter, write=FOnMouseEnter};
__property TNotifyEvent OnMouseLeave = {read=FOnMouseLeave, write=FOnMouseLeave};
};

每当我试图将组件放置在窗体上时,IDE(C++Builder Starter(都会崩溃到桌面。我已经追踪到问题的根源是"BEGIN_MESSAGE_MAP…END_MESSAGE-MAP"部分。如果我把那个部分注释掉,这个组件工作得很好。

我曾经在C++Builder XE5(Professional(中使用过相同的组件,但由于它是由一家我不再合作的公司所有,我没有该组件的二进制文件,所以我必须在这里重写它。据我记忆所及,我所做的与我在XE5中写的完全相同,那个有效,但这个会使IDE崩溃,没有错误消息,没有访问违规,只有普通CTD

有人能帮忙吗?我需要做些什么才能在C++Builder 10.1(柏林(入门版中完成这项工作吗?这是C++Builder的一个错误,还是这是Starter Edition中无法完成的,只能在"付费"版本中完成??或者这种方法已经过时了?如果是,请告诉我"现代化"的C++编译器是如何做到的。

提前谢谢。

您的MESSAGE_MAP被错误终止。在END_MESSAGE_MAP宏中,必须指定组件派生自的基类(TGraphicControl(。

MESSAGE_MAP只是覆盖虚拟Dispatch()方法的一种奇特方式,其中:

  • BEGIN_MESSAGE_MAP声明并打开重写的方法,并打开switch语句
  • MESSAGE_HANDLER(如果您的项目使用ATL,请改用VCL_MESSAGE_HANDLER(为switch声明case语句
  • END_MESSAGE_MAP为未处理的消息调用指定类的Dispatch()方法,关闭switch,并关闭重写的方法

以下是sysmac.h:的声明

#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;                      
}                                         
}

所以,这个代码:

BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGIcon) // <-- error!

由预处理器转换为此代码,这就是编译器所看到的:

virtual void __fastcall Dispatch(void *Message)
{
switch (((PMessage)Message)->Msg)
{
case CM_MOUSEENTER:
CMMouseEnter(*((TMessage *)Message));
break;
case CM_MOUSELEAVE:
CMMouseLeave(*((TMessage *)Message));
break;
default:
TGIcon::Dispatch(Message); // <-- recursive loop!
break;
}
}

正如您所看到的,由于您在END_MESSAGE_MAP中指定自己的组件类(TGIcon(而不是基类(TGraphicControl(,因此当组件接收到未处理的消息时,您将创建一个无休止的递归循环。CCD_ 19再次呼叫CCD_ 20。它需要调用TGraphicControl::Dispatch()(CMMouseEnter()CMMouseLeave()方法也是如此(:

BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGraphicControl) // <-- fixed!