最近写游戏公告服务器,需要按分段落读取RTF格式文本文件内容到内存中,然后下发客户端.
网络上没找到类似功能的代码,费了些功夫研究了一下,感觉在Windows下写些自由度较大的功能都像是在做hack.
// 创建一个临时RichEdit控件
HMODULE hInstRich = ::LoadLibrary("RICHED20.DLL");
ATLASSERT(hInstRich != NULL);
CRichEditCtrl ctrlRichEdit;
ctrlRichEdit.Create(NULL, NULL, NULL, WS_POPUP | ES_MULTILINE);
// 取得ITextDocument接口
IRichEditOle* pRichEditOle = ctrlRichEdit.GetOleInterface();
if(!pRichEditOle) return false;
ITextDocument* pRichDoc = NULL;
pRichEditOle->QueryInterface(__uuidof(ITextDocument), (LPVOID*)&pRichDoc);
SAFE_RELEASE(pRichEditOle);
if(!pRichDoc) return false;
// 打开RTF文件
CComVariant varFileName = szFileName;
HRESULT hr = pRichDoc->Open(&varFileName, tomReadOnly | tomRTF, 0);
if(FAILED(hr))
{
SAFE_RELEASE(pRichDoc);
return false;
}
// 读取RTF文件
CIntArray arrParas;
arrParas.push_back(0);
// 分析文章每个段的位置
int lineCount = ctrlRichEdit.GetLineCount();
for(int i = 0; i < lineCount; i++)
{
char szLineText[16] = { 0 };
int nLineBeginCharIndex = ctrlRichEdit.LineIndex(i);// 行首CharIndex
int nLineLength = ctrlRichEdit.LineLength(nLineBeginCharIndex);
if(nLineLength == 0) continue;
int nLineEndCharIndex = nLineBeginCharIndex + nLineLength;// 行末CharIndex
ctrlRichEdit.GetTextRange(nLineEndCharIndex, nLineEndCharIndex + 1, szLineText);
if(szLineText[0] == '\r')
{
arrParas.push_back(nLineEndCharIndex + 1);
}
}
// 读取每个段的内容到内存
FORMATETC fmtEtc = { RegisterClipboardFormat(CF_RTF), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
for(uint32 i = 0; i < arrParas.size() - 1; i++)
{
ITextRange* pTextRange = NULL;
if(SUCCEEDED(pRichDoc->Range(arrParas[i], arrParas[i+1], &pTextRange)) && pTextRange != NULL)
{
CComVariant varDataObject;
IDataObject* pDataObject = NULL;
varDataObject.vt = VT_UNKNOWN | VT_BYREF;
varDataObject.ppunkVal = (IUnknown**)&pDataObject;
hr = pTextRange->Copy(&varDataObject);
if(SUCCEEDED(hr) && pDataObject != NULL)
{
STGMEDIUM stgMedium = { TYMED_HGLOBAL, 0 };
hr = pDataObject->GetData(&fmtEtc, &stgMedium);
if(SUCCEEDED(hr) && stgMedium.hGlobal != NULL)
{
DWORD nLen = ::GlobalSize(stgMedium.hGlobal);
void* pData = (void*)::GlobalLock(stgMedium.hGlobal);
CMemChunkBase chunk(nLen);
chunk.WriteData(pData, nLen);
m_arrSysMsgs.push_back(chunk);
::GlobalUnlock(pData);
}
}
SAFE_RELEASE(pDataObject);
SAFE_RELEASE(pTextRange);
}
}
SAFE_RELEASE(pRichDoc);
ctrlRichEdit.DestroyWindow();
FreeLibrary(hInstRich);
hInstRich = NULL;