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;
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;
UINT nLength = UINT( AfxReadStringLength(ar, nCharSize) );
if (nCharSize == sizeof(char))
{
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));
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