Search code examples
listviewsubclassc++buildertlistview

TListView detecting ESC or unchanged editing


I am trying to subclass the WindowProc of TListView to detect ESC key press after editing TListView caption (if user cancels editing). ListViewWndProc is getting called clearly, but the code parameter which is supposed to detect that never gets LVN_ENDLABELEDIT value. Why the commented part never gets called? I cannot see the error, it should be happening.

TWndMethod OldWndProc;

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

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
OldWndProc = ListView1->WindowProc;
ListView1->WindowProc = ListViewWndProc;
}

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

void __fastcall TForm1::ListViewWndProc(TMessage &Message)
{
if (Message.Msg == CN_NOTIFY)
    {
    LPNMHDR pnmh = reinterpret_cast<LPNMHDR>(Message.LParam);

    if (pnmh->code == LVN_ENDLABELEDIT) // UPDATE: if LVN_ENDLABELEDIT is replaced with 4294967120 it works
        {

        // !!! THE FOLLOWING NEVER HAPPENS !!!

        // UPDATE: Looks like LVN_ENDLABELEDIT is incorrectly defined in C++ Builder 2010
        // if LVN_ENDLABELEDIT is replaced with 4294967120 the code works

        LV_DISPINFO *pdi = reinterpret_cast<LV_DISPINFO*>(Message.LParam);
        if (pdi->item.pszText == NULL)
            {
            Edit1->Text = "Cancelled";
            return;
            }
        }
    }

OldWndProc(Message);
}

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

void __fastcall TForm1::ListView1Editing(TObject *Sender, TListItem *Item, bool &AllowEdit)
{
Edit1->Text = "Editing";
}

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

void __fastcall TForm1::ListView1Edited(TObject *Sender, TListItem *Item, UnicodeString &S)
{
Edit1->Text = "Done";
}

Solution

  • In C++, the value of LVN_ENDLABELEDEDIT depends on the project's TCHAR_Mapping, which can be changed in the Project Settings via the "_TCHAR maps to" configuration item. By default, _TCHAR is set to wchar_t in C++Builder 2009 and later, unless you migrate a project from an earlier version, in which case it is char by default instead.

    LVN_ENDLABELEDIT is a macro that maps to LVN_ENDLABELEDITA (4294967190) when _TCHAR is char, and to LVN_ENDLABELEDITW (4294967120) when _TCHAR is wchar_t.

    Checking for both constants LVN_ENDLABELEDEDITA and LVN_ENDLABELEDEDITW, like it is done in the Delphi source code, should be OK.

    void __fastcall TForm1::ListViewWndProc(TMessage &Message)
    {
        if (Message.Msg == CN_NOTIFY)
        {
            LPNMHDR pnmh = reinterpret_cast<LPNMHDR>(Message.LParam);
    
            if ((pnmh->code == LVN_ENDLABELEDITA) || (pnmh->code == LVN_ENDLABELEDITW)) 
            {
                LV_DISPINFO *pdi = reinterpret_cast<LV_DISPINFO*>(Message.LParam);
                if (pdi->item.pszText == NULL)
                {
                    Edit1->Text = "Cancelled";
                    return;
                }
            }
        }
    
        OldWndProc(Message);
    }