Click here to Skip to main content
Licence 
First Posted 3 Jun 2003
Views 122,652
Bookmarked 19 times

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

By | 3 Jun 2003 | Article
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

About the Author

leandrobecker

Web Developer

Brazil Brazil

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralNo one is giving the solution Pinmembertmjanarthanan3:23 12 Feb '09  
GeneralLet's start over - I think we can help him PinmemberLarryLeonard6:20 5 Jun '03  
GeneralRe: Let's start over - I think we can help him PinmemberMarcel246:36 5 Jun '03  
GeneralRe: Let's start over - I think we can help him Pinmemberleandrobecker6:46 5 Jun '03  
GeneralRe: Let's start over - I think we can help him PinsussAnonymous6:59 5 Jun '03  
GeneralRe: Let's start over - I think we can help him Pinmemberleandrobecker8:40 5 Jun '03  
GeneralRe: Let's start over - I think we can help him PinsussAnonymous19:16 5 Jun '03  
GeneralRe: Let's start over - I think we can help him PinmemberLarryLeonard7:07 5 Jun '03  
GeneralRe: Let's start over - I think we can help him PinmemberLonnie McCullough20:46 5 Jun '03  
GeneralThe guy doesn't deserve a break. PinmemberLarryLeonard3:53 6 Jun '03  
GeneralRe: The guy doesn't deserve a break. PinmemberLonnie McCullough5:18 6 Jun '03  
GeneralRe: The guy doesn't deserve a break. PinmemberLarryLeonard3:48 9 Jun '03  
GeneralRe: The guy doesn't deserve a break. PinmemberAnna-Jayne Metcalfe3:12 10 Jun '03  
GeneralRe: Let's start over - I think we can help him PinmemberAnna-Jayne Metcalfe3:07 10 Jun '03  
GeneralRe: Let's start over - I think we can help him PinmemberLarryLeonard3:43 10 Jun '03  
GeneralRe: Let's start over - I think we can help him PinmemberAnna-Jayne Metcalfe3:47 10 Jun '03  
GeneralGive him a break, please PinmemberWu Song Da Hu4:46 5 Jun '03  
General... PinmemberTW4:55 5 Jun '03  
GeneralRe: ... Pinmemberleandrobecker12:44 6 Jun '03  
GeneralRe: ... PinmemberTW2:10 7 Jun '03  
GeneralRe: ... PinmemberAnna-Jayne Metcalfe3:03 10 Jun '03  
GeneralRe: ... PinmemberTW6:24 10 Jun '03  
GeneralRe: ... PinmemberAnna-Jayne Metcalfe7:50 10 Jun '03  
GeneralRe: Give him a break, please PinmemberLarryLeonard3:55 6 Jun '03  
GeneralRe: Give him a break, please PinmemberPaolo Messina12:39 6 Jun '03  

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

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120517.1 | Last Updated 4 Jun 2003
Article Copyright 2003 by leandrobecker
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid