LPSTREAM无法读入CString

时间:2018-01-26 00:43:49

标签: c++ stream storage compound-file

我正在尝试使用LPSTREAM将文本读入CString,但它似乎没有正常工作,这是我正在调用的代码:

static HRESULT UTL_ReadStreamTxt(MyStorage* pSrcStg, const char* pszStream, CString* myCStr, int size)
{
        HRESULT     hrRet = STG_E_INVALIDPARAMETER;
        LPSTREAM    lpSrc = NULL;
        ULONG ul;

        TRY
        { 
            USES_CONVERSION;
            HRESULT hrSrc = pSrcStg->GetStg()->OpenStream(CT2COLE(strSrc),          
                                                    NULL,
                                                    STGM_READ | STGM_SHARE_EXCLUSIVE,
                                                    0,
                                                    &lpSrc);
            if (hrSrc != NOERROR)
            {
                hrRet = hrSrc;
            }
            else
            {
                hrRet = lpSrc->Read(&myCStr, size, NULL); // Read into CString
            }

        }

        CATCH_ALL(e)
        {
            hrRet = STG_E_UNKNOWN;
        }
        END_CATCH_ALL


        _AfxRelease((LPUNKNOWN*)&lpSrc);

        return hrRet;
}

当它读入字符串时,Visual Studio会说CString中的数据已损坏。

复合存储的流内容如下:

abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz

我不完全确定我正确使用Read(),如何解决此问题?

1 个答案:

答案 0 :(得分:1)

主要问题是您将错误的指针传递给Read()。您正在传递myCStr参数本身的内存地址,而不是CString的地址,而不是CString所拥有的字符缓冲区的内存地址。代码编译只是因为Read()使用指向缓冲区的简单void*指针,而任何指针都可以隐式转换为void*

另请注意,CString基于TCHAR,它会映射到charwchar_t,具体取决于您是为ANSI / MBCS还是Unicode编译项目。因此,直接从流中读取CString只会在以下情况下正常工作:

  1. 该流包含ANSI字符,TCHAR映射到char

  2. 该流包含UTF-16字符,TCHAR映射到wchar_t

  3. 如果流的字符类型与CString使用的字符类型不匹配,则必须首先将流读入中间缓冲区,然后将其转换为TCHAR,然后才能将其存储到CString

    尝试更像这样的事情:

    static HRESULT UTL_ReadStreamTxt(MyStorage* pSrcStg, const char* pszStream, CString* myCStr, int size)
    {
        HRESULT     hrRet = STG_E_INVALIDPARAMETER;
        LPSTREAM    lpSrc = NULL;
        ULONG       ul;
        LPVOID      buffer;
    
        TRY
        { 
            USES_CONVERSION;
            HRESULT hrSrc = pSrcStg->GetStg()->OpenStream(CT2COLE(strSrc),          
                                                        NULL,
                                                        STGM_READ | STGM_SHARE_EXCLUSIVE,
                                                        0,
                                                        &lpSrc);
            if (hrSrc != S_OK)
            {
                hrRet = hrSrc;
            }
            else
            {
                // if the stream's character type matches TCHAR...
    
                buffer = myCStr->GetBuffer(size / sizeof(TCHAR));
                hrRet = lpSrc->Read(buffer, size, &ul);
                myCStr->ReleaseBuffer(ul / sizeof(TCHAR));
    
                // else, if the stream's character type is 'char' and TCHAR is 'wchar_t'...
    
                CStringA tmp;
                buffer = tmp.GetBuffer(size);
                hrRet = lpSrc->Read(buffer, size, &ul);
                tmp.ReleaseBuffer(ul);
                *myCStr = CString((LPSTR)tmp, tmp.GetLength());
    
                // else, if the stream's character type is 'wchar_t' and TCHAR is 'char'...
    
                CStringW tmp;
                buffer = tmp.GetBuffer(size / sizeof(wchar_t));
                hrRet = lpSrc->Read(buffer, size, &ul);
                tmp.ReleaseBuffer(ul / sizeof(wchar_t));
                *myCStr = CString((LPWSTR)tmp, tmp.GetLength());
    
                // alternatively, you can do the above 2 cases more generically...
    
                typedef CStringT<char or wchar_t> CStreamString;
                CStreamString tmp;
                buffer = tmp.GetBuffer(size / sizeof(CStreamString::XCHAR));
                hrRet = lpSrc->Read(buffer, size, &ul);
                tmp.ReleaseBuffer(ul / sizeof(CStreamString::XCHAR));
                *myCStr = CString((CStreamString::PXSTR)tmp, tmp.GetLength());
            }
        }
    
        CATCH_ALL(e)
        {
            hrRet = STG_E_UNKNOWN;
        }
        END_CATCH_ALL
    
        _AfxRelease((LPUNKNOWN*)&lpSrc);
    
        return hrRet;
    }