c++buildertscrollbox

C++Builder TMouseWheelEvent compiler error


No matter how I attempt to use it, I cannot dynamically create a TScrollBox and assign an OnMouseWheelEvent handler to it. I get the following compiler error:

E2034 Cannot convert 'void (_fastcall * (_closure )(TObject *,TShiftState,int,TPoint &,bool &))(TObject *,TShiftState,int,TPoint &,bool &)' to 'TMouseWheelEvent'

My declaration for the OnMouseWheelEvent handler is correct (as far as I can tell):

....
TScrollBox *sb = new TScrollBox(funnelCharts);
sb->Top = 5000;
sb->Parent = funnelCharts;
sb->Align = alClient;
sb->Height = funnelCharts->ClientHeight;
sb->OnMouseWheel = scrollEvent;
....

// --------------------------------------------------------------

void __fastcall TForm1::scrollEvent(TObject *Sender, TShiftState Shift, int WheelDelta, TPoint &MousePos, bool &Handled)
{
    TScrollBox *scrollbox = dynamic_cast<TScrollBox*>(Sender);
    if (scrollbox)
    {
        for (int i = 1; i < Mouse->WheelScrollLines; i++)
        {
            if (WheelDelta > 0)
            {
                scrollbox->Perform(WM_VSCROLL, SB_LINEUP, 0);
            }
            else
            {
                scrollbox->Perform(WM_VSCROLL, SB_LINEDOWN, 0);
            }
        }
        scrollbox->Perform(WM_VSCROLL, SB_ENDSCROLL, 0);
        Handled = true;
    }
}

Solution

  • This is a compiler error, not a linker error.

    Look at the actual declaration of TMouseWheelEvent in Controls.hpp. Your scrollEvent() method does not match what is actually declared, otherwise you would not be getting the error.

    Depending on whether you are compiling for 32-bit or 64-bit, TMouseWheelEvent (specifically, its MousePos parameter) is declared differently:

    32-bit:

    typedef void __fastcall (__closure *TMouseWheelEvent)(System::TObject* Sender, System::Classes::TShiftState Shift, int WheelDelta, const System::Types::TPoint &MousePos, bool &Handled);
    

    64-bit:

    typedef void __fastcall (__closure *TMouseWheelEvent)(System::TObject* Sender, System::Classes::TShiftState Shift, int WheelDelta, System::Types::TPoint MousePos, bool &Handled);
    

    The reason for this is BCC32 and BCC64 differ in how they pass around 8-byte struct types (like TPoint). This difference is documented on Embarcadero's DocWiki:

    Events with Structures or Sets of 5-8 Bytes Are Not Valid for BCC64

    Other event types affected by this difference include TGetSiteInfoEvent, TMouseWheelUpDownEvent, and TContextPopupEvent.

    To fix this, you will have to #ifdef your code as documented:

    class TForm1 : public TForm
    {
        ...
        #ifndef _WIN64
        void __fastcall scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled);
        #else
        void __fastcall scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, TPoint MousePos, bool &Handled);
        #endif
        ...
    };
    
    ...
    
    #ifndef _WIN64
    void __fastcall TForm1::scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
    #else
    void __fastcall TForm1::scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, TPoint MousePos, bool &Handled)
    #endif
    {
        ...
    }
    

    Or, a little cleaner approach:

    class TForm1 : public TForm
    {
        ...
        void __fastcall scrollEvent(
            TObject* Sender, TShiftState Shift, int WheelDelta,
            #ifndef _WIN64
            const TPoint &MousePos,
            #else
            TPoint MousePos,
            #endif
            bool &Handled);
        ...
    };
    
    ...
    
    void __fastcall TForm1::scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta,
        #ifndef _WIN64
        const TPoint &MousePos,
        #else
        TPoint MousePos,
        #endif
        bool &Handled)
    {
        ...
    }
    

    Or, even cleaner:

    #ifndef _WIN64
    #define SAFE_5TO8_PARAM(type, name) const type &name
    #else
    #define SAFE_5TO8_PARAM(type, name) type name
    #endif
    
    class TForm1 : public TForm
    {
        ...
        void __fastcall scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, SAFE_5TO8_PARAM(TPoint, MousePos), bool &Handled);
        ...
    };
    
    ...
    
    void __fastcall TForm1::scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, SAFE_5TO8_PARAM(TPoint, MousePos), bool &Handled)
    {
        ...
    }