c++mfcmfc-feature-pack

MFC C++ Derive from CEdit and derive GetWindowText


I am deriving from CEdit, to make a custom control. It would be nice, if like the MFC Feature Pack controls (Mask, Browsable) that I could change GetWindowText to actually report back not what is normally displayed on the control (for example, convert the data between hex and decimal, then return back that string).

Is it this possible in a derived CEdit?


Solution

  • Add message map entries for WM_GETTEXT and WM_GETTEXTLENGTH to your derived CEdit class:

    BEGIN_MESSAGE_MAP( CMyEdit, CEdit )
        ON_WM_GETTEXT()
        ON_WM_GETTEXTLENGTH()
    END_MESSAGE_MAP()
    

    As we are overriding these messages we need a method of getting the original text of the edit control without going into endless recursion. For this we can directly call the default window procedure which is named DefWindowProc:

    CStringW CMyEdit::GetTextInternal()
    {
        CStringW text;
        LRESULT len = DefWindowProcW( WM_GETTEXTLENGTH, 0, 0 );
        if( len > 0 )
        {
            // WPARAM = len + 1 because the length must include the null terminator.
            len = DefWindowProcW( WM_GETTEXT, len + 1, reinterpret_cast<LPARAM>( text.GetBuffer( len ) ) );
            text.ReleaseBuffer( len );
        }
        return text;
    }
    

    The following method gets the original window text and transforms it. Anything would be possible here, including the example of converting between hex and dec. For simplicity I just enclose the text in dashes.

    CStringW CMyEdit::GetTransformedText()
    {
        CStringW text = GetTextInternal();
        return L"--" + text + L"--";
    }
    

    Now comes the actual handler for WM_GETTEXT which copies the transformed text to the output buffer.

    int CMyEdit::OnGetText( int cchDest, LPWSTR pDest )
    {
        // Sanity checks
        if( cchDest <= 0 || ! pDest )
            return 0;
    
        CStringW text = GetTransformedText();
    
        // Using StringCchCopyExW() to make sure that we don't write outside of the bounds of the pDest buffer.
        // cchDest defines the maximum number of characters to be copied, including the terminating null character. 
        LPWSTR pDestEnd = nullptr;
        HRESULT hr = StringCchCopyExW( pDest, cchDest, text.GetString(), &pDestEnd, nullptr, 0 );
        // If our text is greater in length than cchDest - 1, the function will truncate the text and
        // return STRSAFE_E_INSUFFICIENT_BUFFER.
        if( SUCCEEDED( hr ) || hr == STRSAFE_E_INSUFFICIENT_BUFFER )
        {
            // The return value is the number of characters copied, not including the terminating null character. 
            return pDestEnd - pDest;
        }
        return 0;
    }
    

    The handler for WM_GETTEXTLENGTH is self-explanatory:

    UINT CMyEdit::OnGetTextLength()
    {
        return GetTransformedText().GetLength();
    }