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

时间:2017-08-29 06:22:38

标签: c++ c++builder-10.1-berlin

我正在编写一个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的一个错误,还是在简化版中无法做到的,它只能在“付费”版本中完成?或者这种方法已经过时了?如果是这样,请告诉我“现代化”的C ++ Builder如何做到这一点。

提前致谢。

1 个答案:

答案 0 :(得分:2)

您的<?php if($_SERVER["REQUEST_METHOD"]=="POST") { $username = filter_input(INPUT_POST,'username'); $password = filter_input(INPUT_POST,'password'); if (isset($username) && !empty($username)) { if (isset($password) && !empty($password)) { $host = "localhost"; $dbusername = "root"; $dbpassword = ""; $dbname = "youtube"; // Create connection $conn = new mysqli($host, $dbusername, $dbpassword, $dbname); // Check connection if (mysqli_connect_error()) { die('Connect Error (' . mysqli_connect_errno() . ') ' . mysqli_connect_error()); } else { $sql = "INSERT INTO account (username, password) values ('$username','$password')"; if ($conn->query($sql)) { echo "New record created successfully"; } else { echo "Error: " . $sql . "<br>" . $conn->error; } $conn->close(); } } else { echo "Password should not be empty"; die(); } } else { echo "Username should not be empty"; die(); } } ?> 未正确终止。在MESSAGE_MAP宏中,您必须指定组件派生自的基类END_MESSAGE_MAP)。

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

  • Dispatch()声明并打开重写的方法,并打开BEGIN_MESSAGE_MAP语句
  • switch(如果您的项目使用ATL,则使用MESSAGE_HANDLER)为VCL_MESSAGE_HANDLER
  • 声明case语句
  • switch为未处理的邮件调用指定类的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; } } 中指定了自己的组件类(TGIcon)而不是基类(TGraphicControl),所以在创建无限递归循环时组件接收未处理的消息。 END_MESSAGE_MAP再次致电TGIcon::Dispatch()。它需要改为调用TGIcon::Dispatch()(您的TGraphicControl::Dispatch()CMMouseEnter()方法也是如此):

CMMouseLeave()