在MFC的SDI中,使用CHtmlView::GetSource来获取网页源码,保存到本地,发现中文中的一部分乱码,有些中文正常。自己先试着转码等各种尝试,发现一无所获。网上也没有正确的解决方案。
自己跟踪CHtmlView::GetSource函数内,在ViewHtml.cpp文件的1083行处,有如下代码:
bRetVal = TRUE; TRY { refString = CString(pstr, statStg.cbSize.LowPart); } CATCH_ALL(e) { bRetVal = FALSE; DELETE_EXCEPTION(e); }
关键处在:refString = CString(pstr, statStg.cbSize.LowPart);
其实就是在UNICODE情况下,CString在构造时,使用了LPCSTR或者char*来构造CString时的构造函数。但是在构造这个CString内部,会调用到如下函数:
static void __cdecl ConvertToBaseType( _Out_writes_(nDestLength) LPWSTR pszDest, _In_ int nDestLength, _In_ LPCSTR pszSrc, _In_ int nSrcLength = -1) throw() { // nLen is in wchar_ts ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength ); }
内部有对LPCSTR或char*进行字符转换。
中文的一部分乱码,正是由这个地方产生的。
别奢望用CStringA str(strHtml)来转换回来,转了之后的内容,依然有一部分的中文乱码。
我的解决办法是,将CHtmlView::GetSource的代码Copy出来,直接返回CStringA的内容,并用CStringA的内容,来保存文件。结果就正常了。
我的代码如下:
BOOL CMFCBrowserView::GetMySource(CStringA& strRef) { BOOL bRetVal = FALSE; CComPtr<IDispatch> spDisp; m_pBrowserApp->get_Document(&spDisp); if ( spDisp == NULL ) { return bRetVal; } HGLOBAL hMemory; hMemory = GlobalAlloc(GMEM_MOVEABLE, 0); if ( hMemory == NULL ) { return bRetVal; } CComQIPtr<IPersistStreamInit> spPersistStream = spDisp; if ( spPersistStream == NULL ) { GlobalFree(hMemory); return bRetVal; } CComPtr<IStream> spStream; HRESULT hRes = CreateStreamOnHGlobal(hMemory, TRUE, &spStream); if ( FAILED(hRes) ) { GlobalFree(hMemory); return bRetVal; } spPersistStream->Save(spStream, FALSE); STATSTG statStg; spStream->Stat(&statStg, STATFLAG_NONAME); LPCSTR pstr = static_cast<LPCSTR>(GlobalLock(hMemory)); if ( pstr == NULL ) { GlobalFree(hMemory); return bRetVal; } // Stream is expected to be ANSI (CP-ACP). CString constructor // will convert implicitly, and truncate to correct length. bRetVal = TRUE; CStringA strV(pstr, statStg.cbSize.LowPart); strRef = strV; GlobalUnlock(hMemory); GlobalFree(hMemory); return bRetVal; }
主要问题:就出在CString内部构造时,对字符串的转换。如果需要CString的字符串,可能需要自己来转换成宽字符,然后赋值给CString。这个只是猜测,没有进行测试。