BEGIN_MESSAGE_MAP 导致 C++ Builder 10.1 崩溃到桌面
BEGIN_MESSAGE_MAP caused C++ Builder 10.1 to crash to desktop
我正在编写一个 VCL 组件 TGIcon,以模仿 windows 桌面中的图标,在我决定将 MouseEnter 和 MouseLeave 事件添加到组件之前,它一直运行良好。我遵循了以下指南:Embarcadero Community
这是我的代码 (header):
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(专业版)中使用相同的组件,但由于它属于一家我不再与之合作的公司,所以我没有该组件的二进制文件,所以我必须re-write 就在这里。据我所知,我所做的与我在 XE5 中编写的完全相同,那个可以工作但是这个会崩溃IDE,没有错误消息,没有访问冲突,只是普通的 CTD。
有人可以帮忙吗,我需要做些什么才能在 C++ Builder 10.1(柏林)入门版中完成这项工作?这是C++Builder 的bug 还是这是在Starter Edition 中不能完成的,只能在'paid' 版本中完成??还是这种方法已经过时了?如果是,请告诉我 "modernized" C++ Builder 是如何做到的。
提前致谢。
您的 MESSAGE_MAP
未正确终止。在 END_MESSAGE_MAP
宏中,您必须指定组件派生自的 base class (TGraphicControl
).
A MESSAGE_MAP
只是一种覆盖虚拟 Dispatch()
方法的奇特方式,其中:
BEGIN_MESSAGE_MAP
声明并打开覆盖的方法,并打开一个switch
语句
MESSAGE_HANDLER
(如果您的项目使用 ATL,则使用 VCL_MESSAGE_HANDLER
)为 switch
声明 case
语句
END_MESSAGE_MAP
为未处理的消息调用指定 class 的 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;
}
}
如您所见,因为您指定的是自己的组件 class (TGIcon
) 而不是 [=17= 中的基础 class (TGraphicControl
) ],当组件收到未处理的消息时,您正在创建一个无限递归循环。 TGIcon::Dispatch()
再次呼叫 TGIcon::Dispatch()
。它需要调用 TGraphicControl::Dispatch()
(你的 CMMouseEnter()
和 CMMouseLeave()
方法也是如此):
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGraphicControl) // <-- fixed!
我正在编写一个 VCL 组件 TGIcon,以模仿 windows 桌面中的图标,在我决定将 MouseEnter 和 MouseLeave 事件添加到组件之前,它一直运行良好。我遵循了以下指南:Embarcadero Community
这是我的代码 (header):
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(专业版)中使用相同的组件,但由于它属于一家我不再与之合作的公司,所以我没有该组件的二进制文件,所以我必须re-write 就在这里。据我所知,我所做的与我在 XE5 中编写的完全相同,那个可以工作但是这个会崩溃IDE,没有错误消息,没有访问冲突,只是普通的 CTD。
有人可以帮忙吗,我需要做些什么才能在 C++ Builder 10.1(柏林)入门版中完成这项工作?这是C++Builder 的bug 还是这是在Starter Edition 中不能完成的,只能在'paid' 版本中完成??还是这种方法已经过时了?如果是,请告诉我 "modernized" C++ Builder 是如何做到的。
提前致谢。
您的 MESSAGE_MAP
未正确终止。在 END_MESSAGE_MAP
宏中,您必须指定组件派生自的 base class (TGraphicControl
).
A MESSAGE_MAP
只是一种覆盖虚拟 Dispatch()
方法的奇特方式,其中:
BEGIN_MESSAGE_MAP
声明并打开覆盖的方法,并打开一个switch
语句MESSAGE_HANDLER
(如果您的项目使用 ATL,则使用VCL_MESSAGE_HANDLER
)为switch
声明 END_MESSAGE_MAP
为未处理的消息调用指定 class 的Dispatch()
方法,关闭switch
,并关闭覆盖的方法。
case
语句
以下是来自 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;
}
}
如您所见,因为您指定的是自己的组件 class (TGIcon
) 而不是 [=17= 中的基础 class (TGraphicControl
) ],当组件收到未处理的消息时,您正在创建一个无限递归循环。 TGIcon::Dispatch()
再次呼叫 TGIcon::Dispatch()
。它需要调用 TGraphicControl::Dispatch()
(你的 CMMouseEnter()
和 CMMouseLeave()
方法也是如此):
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGraphicControl) // <-- fixed!