Click here to Skip to main content
15,904,023 members
Articles / Desktop Programming / MFC
Article

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

Rate me:
Please Sign up or sign in to vote.
1.14/5 (40 votes)
3 Jun 20031 min read 168.9K   20   79
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<BASETYPE, StringTraits>& 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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Brazil Brazil
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: Why some people are so bothered with my code ? Pin
leandrobecker5-Jun-03 4:05
leandrobecker5-Jun-03 4:05 
AnswerRe: Why some people are so bothered with my code ? Pin
anonymouss5-Jun-03 6:47
anonymouss5-Jun-03 6:47 
GeneralHe must be a troll... Pin
Anonymous4-Jun-03 14:07
Anonymous4-Jun-03 14:07 
GeneralRe: He must be a troll... Pin
leandrobecker4-Jun-03 15:00
leandrobecker4-Jun-03 15:00 
GeneralRe: He must be a troll... Pin
dog_spawn4-Jun-03 15:19
dog_spawn4-Jun-03 15:19 
GeneralRe: He must be a troll... Pin
LarryLeonard5-Jun-03 3:16
LarryLeonard5-Jun-03 3:16 
GeneralI'm not abusing ... Pin
leandrobecker4-Jun-03 12:01
leandrobecker4-Jun-03 12:01 
GeneralRe: I'm not abusing ... Pin
Josh Booth4-Jun-03 13:55
Josh Booth4-Jun-03 13:55 
leandrobecker wrote:
The operators works very well, the CString is much more than a simple string like in 'C'. If a person do not know the capabilities of the CString, please, do not say things that you do not know.

That is hilarious! Did the author consider he didn’t “know the capabilities of the CString”? If you read the documentation about the CString = operator where your so called bug exists you would see that it clearly says:
"lpsz Specifies a pointer to a null-terminated character string."
Its documented and after all, bugs are only undocumented features. Further, if it worked the way the author believes it should I think we would have a real bug as CString bob = "hello world!" would assign till eternity to the string.

I have never written an article for codeproject so far be it from me to want to knit pick on peoples articles, however, I really think this article should be removed it demonstrates a clear lack of understanding of fundamental C/C++ concepts and is of absolutely no value. And I don’t think I'd want to rely on any encryption written by this guy. Hmmm | :| Hmmm | :|


-----------------
the Truth is freedom.
GeneralRe: I'm not abusing ... Pin
dog_spawn4-Jun-03 15:33
dog_spawn4-Jun-03 15:33 
GeneralWhy remove it? Pin
thorek5-Jun-03 3:54
thorek5-Jun-03 3:54 
GeneralRe: Why remove it? Pin
LarryLeonard5-Jun-03 5:57
LarryLeonard5-Jun-03 5:57 
Generalcomic magic Pin
dog_spawn4-Jun-03 15:31
dog_spawn4-Jun-03 15:31 
GeneralNo, no, no, you're abusing CString Pin
LarryLeonard4-Jun-03 9:57
LarryLeonard4-Jun-03 9:57 
GeneralRe: No, no, no, you're abusing CString Pin
Jörgen Sigvardsson4-Jun-03 10:35
Jörgen Sigvardsson4-Jun-03 10:35 
GeneralRe: No, no, no, you're abusing CString Pin
leandrobecker4-Jun-03 10:53
leandrobecker4-Jun-03 10:53 
GeneralRe: No, no, no, you're abusing CString Pin
Anonymous4-Jun-03 13:16
Anonymous4-Jun-03 13:16 
GeneralRe: No, no, no, you're abusing CString Pin
peterchen4-Jun-03 15:20
peterchen4-Jun-03 15:20 
GeneralRe: No, no, no, you're abusing CString Pin
dog_spawn4-Jun-03 15:34
dog_spawn4-Jun-03 15:34 
GeneralRe: No, no, no, you're abusing CString Pin
Anonymous4-Jun-03 11:13
Anonymous4-Jun-03 11:13 
GeneralMany people are ... Pin
leandrobecker4-Jun-03 6:19
leandrobecker4-Jun-03 6:19 
GeneralRe: Many people are ... Pin
Steve Mayfield4-Jun-03 8:11
Steve Mayfield4-Jun-03 8:11 
GeneralRe: Many people are ... Pin
John M. Drescher4-Jun-03 9:54
John M. Drescher4-Jun-03 9:54 
GeneralRe: Many people are ... Pin
leandrobecker4-Jun-03 10:50
leandrobecker4-Jun-03 10:50 
GeneralRe: Many people are ... Pin
John M. Drescher4-Jun-03 10:59
John M. Drescher4-Jun-03 10:59 
GeneralRe: Many people are ... Pin
leandrobecker4-Jun-03 12:04
leandrobecker4-Jun-03 12:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.