2017-08-29 12 views
0

Windowsデスクトップのアイコンを模倣するためにVCLコンポーネント(TGIcon)を作成していますが、コンポーネントにMouseEnterイベントとMouseLeaveイベントを追加するまではうまくいきました。私はからのガイドに続く:Embarcadero CommunityBEGIN_MESSAGE_MAPにより、C++ Builder 10.1がデスクトップにクラッシュする

を、ここで私のコード(ヘッダ)である:私はフォームにコンポーネントを配置しようとするたびに

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のスターター)がデスクトップにクラッシュしていました。私は、問題の原因を "BEGIN_MESSAGE_MAP ... END_MESSAGE_MAP"の部分とみなしました。私がその部分をコメントアウトすると、コンポーネントは正常に動作します。

私は同じコンポーネントをC++ Builder XE5(Professional)で使用していましたが、これは私がもう使用していない会社が所有しているため、コンポーネントのバイナリはありません。それをここに書いてください。私が覚えている限り、私が行ったことは、私がXE5で書いたものとまったく同じです、IDEがクラッシュするでしょう、エラーメッセージなし、アクセス違反なし、単純なCTDです。

C++ Builder 10.1(Berlin)Starter Editionでこの作業を行うために必要なことがありますか?これはC++ Builderのバグですか、これは初心者モードではできないことですか?それは「有料版」でしかできないのですか?または、このメソッドはすでに廃止されていますか?もしそうなら、 "近代化された" C++ Builderがどうやってそれをしているのか教えてください。

ありがとうございます。

+0

リンクは(ほとんど20歳)本当に、本当に古い記事です。私が心配しているのは、 '__fastcall'呼び出し規約を使用することです。私はしばらくの間、これらのメッセージハンドラで作業していないので、次のステートメントは間違っているかもしれませんが、それらの関数は代わりに '__stdcall'規約を使用している必要があります。少なくとも、あなたはそれを試すことができます。これらの呼び出し規則についてのいくつかのコンテキストについては、 [this](https://stackoverflow.com/questions/15047758/cdecl-stdcall-and-fastcall-are-all-called-the-exact-same-way)。 –

+0

まだCTDである__stdcallを試しました。私は記事が古いことを知っている、私はC + + Builder 6.0以降のイベント処理の種類を使用しています。私はXE5でBEGIN_MESSAGE_MAPのインラインコードについて苦情があった時には廃止になると思っていましたが、Embarcaderoはこれに関する情報を全く更新していません。少なくともGoogle経由では見つかりませんでした。とにかくありがとう。 –

答えて

1

MESSAGE_MAPが正しく終了しません。 END_MESSAGE_MAPマクロでは、コンポーネントが(TGraphicControl)から派生する基本クラスをと指定する必要があります。

  • BEGIN_MESSAGE_MAPプロジェクト場合は代わりにVCL_MESSAGE_HANDLERを使用します(宣言し、オープンしオーバーライドされたメソッドを、そしてswitch声明
  • MESSAGE_HANDLERを開きます。

    MESSAGE_MAPは、仮想Dispatch()メソッドをオーバーライドするだけの空想の方法ですATLを使用します)宣言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; 
    } 
} 

あなたが見ることができるように、あなたは(あなた自身のコンポーネントクラスを指定しているので、 (TGraphicControl)の代わりにEND_MESSAGE_MAPに設定すると、コンポーネントが未処理のメッセージを受け取ったときに無限ループが作成されます。 TGIcon::Dispatch()はもう一度TGIcon::Dispatch()と呼び出しています。それは(そう、あなたのCMMouseEnter()CMMouseLeave()メソッドを実行する)代わりにTGraphicControl::Dispatch()を呼び出す必要があります:あなたが提供する

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

はい、本当に...これについて忘れた私の愚かなこと...ケースが解決しました、ありがとう、レミー・ルボー。 –

関連する問題