65.9K
CodeProject is changing. Read more.
Home

Differences in the behaviour of CString >> and << using MFC 7 and double '\0' ended strings (like REG_MULTI_SZ)

starIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIconemptyStarIcon

1.14/5 (35 votes)

Jun 4, 2003

1 min read

viewsIcon

171597

Differences in the behaviour of CString >> and << using MFC 7 and double '\0' ended strings (like REG_MULTI_SZ) and a workaround

Introduction

This article explain the behaviour diference using CString with binary buffers (GetBuffer or GetBufferSetLength using REG_MULTI_SZ) and the serialization (more precisally the read operation, the write works fine). The problem occurs when your buffer contains '\0' at the middle of the buffer. The CArchive << writes all buffer to the file but the CArchive >> reads all data from the file as expected in a temporary buffer and performs an simple assignment to the CString using the CString operator=. This is the problem, the CString operator = stops in a '\0'. Below is the MFC code with the bug and a workaround to try solve the problem.

Peoples can say, why this ? Use an array. Yes I agree with all of then, but, I my case I can't use an array. This is the first time in 5 years of MFC development that I must made this "heresy" like some people consider it.

I have changed the title of the article to behaviour diference because the opinion of the people.

Using the code

This is the MFC code:

template< typename BaseType, class StringTraits >
    CArchive& AFXAPI operator>>(CArchive& ar, ATL::CStringT& str)
{
    int nCharSize;  // 1 = char, 2 = wchar_t
    UINT nLength = UINT( AfxReadStringLength(ar, nCharSize) );
    if (nCharSize == sizeof(char))
    {
        ATL::CTempBuffer< char > pszBufferA(nLength+1);

        pszBufferA[nLength] = '\0';
        UINT nBytesRead = ar.Read(pszBufferA, nLength*sizeof(char));
        if (nBytesRead != (nLength*sizeof(char)))
            AfxThrowArchiveException(CArchiveException::endOfFile);
        str = pszBufferA;
    }
    else
    {
        ASSERT(nCharSize == sizeof(wchar_t));

        ATL::CTempBuffer< wchar_t > pszBufferW( nLength+1 );

        pszBufferW[nLength] = L'\0';
        UINT nBytesRead = ar.Read(pszBufferW, nLength*sizeof(wchar_t));
        if (nBytesRead != (nLength*sizeof(wchar_t)))
            AfxThrowArchiveException(CArchiveException::endOfFile);
        str = pszBufferW;
    }

    return ar;
}

This is a workaround:

EXPORT_LCC UINT LCC_ReadBinaryCStringFromArchive(CArchive& ar, CString& str)
{
    ASSERT(ar.IsLoading());

    UINT nBytesRead;
    int nCharSize;  // 1 = char, 2 = wchar_t
    UINT nLength = UINT( AfxReadStringLength(ar, nCharSize) );
    if (nCharSize == sizeof(char))
    {
        // is UNICODE ? if nLength is 10 chars we must 5 wchar_t
        // to hold 10 chars
        if (nCharSize != sizeof(TCHAR))
            nBytesRead = ar.Read(str.GetBufferSetLength(nLength / sizeof 
                                (TCHAR) + (nLength % sizeof(TCHAR))),
                                nLength * sizeof(char));
        else
            nBytesRead = ar.Read(str.GetBufferSetLength(nLength),
                                 nLength*sizeof(char));

        if (nBytesRead != (nLength*sizeof(char)))
            AfxThrowArchiveException(CArchiveException::endOfFile);
    }
    else
    {
        ASSERT(nCharSize == sizeof(wchar_t));

        // not is UNICODE ? if nLength is 10 w_chars we must
        // 20 chars to hold 10 w_chars
        if (nCharSize != sizeof(TCHAR)) 
            nBytesRead = ar.Read(str.GetBufferSetLength(nLength * 
                         sizeof(TCHAR)), nLength * sizeof(wchar_t));
        else
            nBytesRead = ar.Read(str.GetBufferSetLength(nLength),
                                 nLength*sizeof(wchar_t));

        if (nBytesRead != (nLength*sizeof(wchar_t)))
            AfxThrowArchiveException(CArchiveException::endOfFile);
    }
    return nBytesRead;
}

I know that not is the same facility of CArchive overloaded operator >> but works for me. Use CString only if you need. If not, use an array.

History