I am writing a VCL componenet, TGIcon, to mimic the Icons in windows desktop, it has been working fine until I decided to add MouseEnter and MouseLeave events to the component. I followed guides from: Embarcadero Community
and here is my code (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};
};
Whenever I try to place the component on a Form, the IDE (C++ Builder Starter) would crash to desktop. I have traced the source of problem to be the "BEGIN_MESSAGE_MAP...END_MESSAGE_MAP" part. If I comment out that part, the component works fine.
I used to have the same component working in C++Builder XE5 (Professional) but since that's owned by a company I no longer work with, I don't have the binary of the component, so I have to re-write it here. As far as I can remember, what I did is exactly the same as the one I wrote in XE5, that one works but this one would crash the IDE, no error message, no Access Violation, just plain CTD.
Can someone please help, is there anything I need to do to make this work in C++ Builder 10.1 (Berlin) Starter Edition? Is this a bug of C++Builder or is this what cannot be done in Starter Edition, that it only can be done in the 'paid' editions?? Or is this method already obsolete? If so please show me how the "modernized" C++ Builder do it.
Thanks in advance.
Your
MESSAGE_MAP
is terminated incorrectly. In theEND_MESSAGE_MAP
macro, you must specify the base class that your component derives from (TGraphicControl
).A
MESSAGE_MAP
is just a fancy way to override the virtualDispatch()
method, where:BEGIN_MESSAGE_MAP
declares and opens the overridden method, and opens aswitch
statementMESSAGE_HANDLER
(useVCL_MESSAGE_HANDLER
instead if your project uses ATL) declarescase
statements for theswitch
END_MESSAGE_MAP
calls theDispatch()
method of the specified class for unhandled messages, closes theswitch
, and closes the overridden method.Here are the declarations from
sysmac.h
:So, this code:
Gets translated by the preprocessor to this code, which is what the compiler sees:
As you can see, since you are specifying your own component class (
TGIcon
) instead of the base class (TGraphicControl
) inEND_MESSAGE_MAP
, you are creating an endless recursion loop when the component receives an unhandled message.TGIcon::Dispatch()
is callingTGIcon::Dispatch()
again. It needs to callTGraphicControl::Dispatch()
instead (so do yourCMMouseEnter()
andCMMouseLeave()
methods):