Mary Ellen Bench
Mary Ellen Bench

Reputation: 589

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?

Upvotes: 3

Views: 1322

Answers (2)

Mary Ellen Bench
Mary Ellen Bench

Reputation: 589

Thanks to everyone for pointing me in the right direction. I tried OnGetText, but the problem seemed to be I couldn't get the underlying string or it would crash when calling GetWindowText (or just called OnGetText again...and couldn't find the underlying string).

After seeing what they did on masked control, I did a simpler answer like this. Are there any drawbacks? It seemed to not cause any issues or side effects...

Derive directly from GetWindowText

void CConvertibleEdit::GetWindowText(CString& strString) const
{
    CEdit::GetWindowText(strString);

    ConvertibleDataType targetDataType;
    if (currentDataType == inputType)
    {

    }
    else
    {
        strString = ConvertEditType(strString, currentDataType, inputType);
    }
}

Upvotes: 0

zett42
zett42

Reputation: 27756

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();
}

Upvotes: 3

Related Questions