65.9K
CodeProject 正在变化。 阅读更多。
Home

MFC 7 中 CString 的 >> 和 << 行为差异,以及双 '\0' 结尾字符串(如 REG_MULTI_SZ)

starIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIconemptyStarIcon

1.14/5 (35投票s)

2003年6月4日

1分钟阅读

viewsIcon

172281

MFC 7 中 CString 的 >> 和 << 行为差异,以及双 '\0' 结尾字符串(如 REG_MULTI_SZ)和一个解决方法

引言

本文解释了在使用 CString 处理二进制缓冲区(使用 REG_MULTI_SZ 的 GetBuffer 或 GetBufferSetLength)以及序列化(更准确地说,是读取操作,写入操作工作正常)时,行为上的差异。 当缓冲区中间包含 '\0' 时,问题就会发生。 CArchive << 将所有缓冲区写入文件,但 CArchive >> 将文件中的所有数据按预期读取到临时缓冲区中,并使用 CString 运算符 = 将其分配给 CString。 这就是问题所在,CString 运算符 = 在 '\0' 处停止。 以下是包含错误的 MFC 代码以及尝试解决问题的解决方法。

有人可能会说,为什么这样? 使用数组。 我同意他们的观点,但是,在我的情况下,我无法使用数组。 这是我在 5 年 MFC 开发生涯中第一次必须做出这种“异端”行为,就像有些人认为的那样。

我更改了文章的标题,改为行为差异,因为人们的意见。

使用代码

这是 MFC 代码

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

这是一个解决方法

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

我知道这与重载的 CArchive 运算符 >> 的便利性并不相同,但它对我有用。 只有在需要时才使用 CString。 如果不需要,请使用数组

历史

© . All rights reserved.