为方便读者使用excel内存打开文件,对于使用方法做如下解释,注意彩色字体提示。
第一步。
.h头文件包含
extern "C"
{
#include "InjectExcel.h"
}
.cpp中操作
_cUnpAbaoExcel a(new _cMyExcel(true));
。。。。
CString SqlStr;
if(a->CreateNewApp()==FALSE)
{
BOOST_THROW_EXCEPTION(
_cMyExceptionImpl(_T("Application创建失败,请确保正确安装了非精简excel 2003或excel 2007版本!"),this));
}
。。。。。。
if(IsXLSFile(m_TongYongTongJiExcelFile)==false)//判断是否是excel文件
。。。。。。
_cUnpAbaoExcel aMoBan(new _cMyExcel(a->m_unpApp->m_lpDispatch));
。。。。。。
DWORD ProcId;
GetWindowThreadProcessId((HWND)aMoBan->m_unpApp->get_Hwnd(), &ProcId);
if(FALSE==SetHookCreateFileFuncNewVersion(ProcId,autoDel.chFileName,autoDel.chStreamName,
autoDel.chSecFileName,autoDel.chSecStreamName,&CurrentExcelProcHandle,oldcode))
{
BOOST_THROW_EXCEPTION(
_cMyExceptionImpl(_T("设置附加程序失败!"),this));
}
中间步骤
CString strAccordingFileName=theApp.strTempPathFullName+_T("\\")+chSecFileName;
aMoBan->openXml(
strAccordingFileName);
LPDISPATCH tmp;
do{
aMoBan->SelectSheet(1);
AbaoRange b2;
b2=aMoBan->get_UsedRange();
COleVariant vOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR),
vTrue((short)TRUE),
vFalse((short)FALSE),
vLookAt((long)xlWhole);
COleVariant vWhat(_T("<?xml version=\"1.0\"?>"));
tmp=b2.Find(vWhat,vOptional,vOptional,vLookAt,vOptional,xlNext,vFalse,vTrue,vOptional);
if(tmp==NULL)
{
break;
}
aMoBan->openXml(strAccordingFileName);
}while(tmp!=NULL);//多打开2次,有时不稳定,希望有时间的读者找找原因,一旦正常打开,就完成了xml转换成对象了
BOOL CFormViewFormatTrans::DoSomethingByUsingExcelApp(
_cUnpAbaoExcel& aMoBan,
const unique_ptr<_cLstOfLstsFilteredMultCos>&filteredLst,
unique_ptr<_cDataBaseCommonVar>& pUniq_ptr_DBCommVar,
const unique_ptr<_sMaxMinMonth>&pMaxMinMonth,bool IsMerged
)
最后一步。
if(FALSE==FreeHookCreateFileFunc(CurrentExcelProcHandle,oldcode))
{
BOOST_THROW_EXCEPTION(_cMyExceptionImpl(_T("释放&*(667失败!"),this));
}
。。。。。。
}catch(std::exception & exp )
{
if(CurrentExcelProcHandle!=NULL)
{
FreeHookCreateFileFunc(CurrentExcelProcHandle,oldcode);
}
exp.what();
return FALSE;
}
补充:
对于内存打开文件名需要专门的命名规则,以保证打开其他文件不受影响。
wcscpy_s(chFileName,15,L"a@#$140816.xls");
wcscpy_s(chStreamName,28,L"a@#$140816.xls:Stream:$DATA");
wcscpy_s(chSecFileName,15,L"b@#$140816.xls");
wcscpy_s(chSecStreamName,28,L"b@#$140816.xls:Stream:$DATA");
hSecStream=0;
hStream=0;
memset(hTmpStream,0,sizeof(HANDLE)*12);
CString strStreamName=theApp.strTempPathFullName+_T("\\")+chStreamName;
TCHAR diskChar=strStreamName.GetAt(0);
TCHAR lpVolumeNameBuffer[1024]; //硬盘卷标名称
DWORD dwVolumeSerialNumber; //序列号
DWORD dwMaximumComponentLength; //文件名最大长度
DWORD FileSystemFlags; //文件系统标志
TCHAR lpFileSystemNameBuffer[1024];//文件系统名称
CString strDisk;
strDisk.Format(_T("%c:\\\\"),diskChar);
if(!GetVolumeInformation(strDisk,
lpVolumeNameBuffer,1024,
&dwVolumeSerialNumber,
&dwMaximumComponentLength,
&FileSystemFlags,
lpFileSystemNameBuffer,1024))
{
BOOST_THROW_EXCEPTION(_cMyExceptionImpl(_T("判断文件系统失败!"),m_OwnerPtr));
}
CString tmpFileSystemName=lpFileSystemNameBuffer;
if(tmpFileSystemName!=_T("NTFS"))
{
BOOST_THROW_EXCEPTION(_cMyExceptionImpl(_T("失败,请将本程序及附带列表文件放在NTFS分区上,不要放在")+
tmpFileSystemName+_T("盘上!"),m_OwnerPtr));
}
if(PathFileExists(strStreamName))
{
if(DeleteFile(strStreamName)==FALSE)
{
BOOST_THROW_EXCEPTION(_cMyExceptionImpl(_T("删除临时文件失败,请手动删除本程序temp文件夹下的文件,可能需要手动到进程管理器终止excel.exe应用程序!"),m_OwnerPtr));
//return FALSE;
}
}
hStream = CreateFile( strStreamName, // Filename
GENERIC_WRITE|GENERIC_READ, // Desired access
FILE_SHARE_WRITE|FILE_SHARE_READ, // Share flags
NULL, // Security Attributes
CREATE_ALWAYS, // Creation Disposition
0, // Flags and Attributes
NULL ); // OVERLAPPED pointer
if( hStream == INVALID_HANDLE_VALUE )
{
BOOST_THROW_EXCEPTION(_cMyExceptionImpl(_T("生成临时文件失败!"),m_OwnerPtr));
}
CString strSecStreamName=theApp.strTempPathFullName+_T("\\")+chSecStreamName;
if(PathFileExists(strSecStreamName))
{
if(DeleteFile(strSecStreamName)==FALSE)
{
BOOST_THROW_EXCEPTION(_cMyExceptionImpl(_T("删除临时文件失败,请手动删除本程序temp文件夹下的文件,可能需要手动到进程管理器终止excel.exe应用程序!"),m_OwnerPtr));
//return FALSE;
}
}
hSecStream = CreateFile( strSecStreamName, // Filename
GENERIC_WRITE|GENERIC_READ, // Desired access
FILE_SHARE_WRITE|FILE_SHARE_READ, // Share flags
NULL, // Security Attributes
CREATE_ALWAYS, // Creation Disposition
0, // Flags and Attributes
NULL ); // OVERLAPPED pointer
if( hSecStream == INVALID_HANDLE_VALUE )
{
BOOST_THROW_EXCEPTION(_cMyExceptionImpl(_T("生成临时文件失败!"),m_OwnerPtr));
}
关于xml文件的生成:
BOOL CFormViewFormatTrans::WriteListToTmpXmlFile(
const unique_ptr<_cLstOfLstsFilteredMultCos>&filteredLst
,unique_ptr<_cDataBaseCommonVar>& pUniq_ptr_DBCommonVar,
const CString &LieBiaoXlsFileName,HANDLE& hStream,HANDLE &hSecStream,
XmlContentInfo& xmlInfoObj,
CString &outStrXmlTmpFileFullName,bool isVLst)
{
CString SheetName2,strTmp;
CString SheetName;
//long TimeSum=0;
CString strTmp3=_T(""),strTmp4=_T(""),strTmp5=_T("");
COleSafeArray saRet,saRetComment;
COleSafeArray saRetRS;
DWORD numElements[2];
DWORD numElementsComment[2];
//long t1=::GetTickCount();
CStringA TmpUTF8CStr;
CString SheetNamePrefix;
if(isVLst==true)
{
SheetNamePrefix.Format(_T("%d-"),VIndex);
VIndex++;
}
else
{
SheetNamePrefix=_T("");
}
try{
CString strFileName;
int nPos=LieBiaoXlsFileName.ReverseFind('.');
if(nPos!=-1)
{
strFileName=LieBiaoXlsFileName.Left(nPos); // 结尾没有 '\'
}
strFileName=_T("jklS@")+strFileName+_T(".xml");
CString XMLFileName=::GetAppPath();
XMLFileName+=_T("\\")+strFileName;
outStrXmlTmpFileFullName=XMLFileName;
//moBanFile.Open(XMLFileName,CFile::modeCreate|CFile::modeWrite);
char *TmpUTF8CStrCh=UnicodeToUtf8(xmlInfoObj.m_TmplCStrFileHeader);
TmpUTF8CStr=TmpUTF8CStrCh;
free(TmpUTF8CStrCh);
DWORD BytesWritten;
WriteFile(hStream,TmpUTF8CStr.GetBuffer(),
TmpUTF8CStr.GetLength(),&BytesWritten,NULL);
TmpUTF8CStr.ReleaseBuffer();
list<shared_ptr< _cListOfOneCompanyDBRows >>::const_reverse_iterator
it__cListOfOneCompanyDBRows;
it__cListOfOneCompanyDBRows=filteredLst->m_pSmartList->crbegin();
numElements[0] = 12;
numElements[1] = m_TaiZhangMoBanFormat.ColumnFormatMap->size();
numElementsComment[0] = 12;
numElementsComment[1] = numElements[1];
int commentColumn=0;
CString strTmpQitaShui;
list<shared_ptr< _cOneDBRowOfCompany >>::const_iterator it__cOneDBRowOfCompany;
COleVariant vOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR),
vTrue((short)TRUE),
vFalse((short)FALSE),
vLookAt((long)xlWhole);
CString SqlStr;
//最好不用recordset 的getrecordcount方法,因为会不准确
SqlStr.Format(_T("select Count(*) as rscount from %s")
,filteredLst->m_TBLName);
int rscount=0;
pUniq_ptr_DBCommonVar->pRs->Open(SqlStr);
pUniq_ptr_DBCommonVar->pRs->GetFieldValue(_T("rscount"),rscount);
if(rscount<=0)
{
BOOST_THROW_EXCEPTION(_cMyExceptionImpl(_T("计算公司数量失败!"),this));
}
SqlStr.Format(_T("select F1,F2,F3,F4,F5 from %s")
,filteredLst->m_TBLName);
pUniq_ptr_DBCommonVar->pRs->Open(SqlStr);
saRetRS.Attach(pUniq_ptr_DBCommonVar->pRs->m_pRecordset->GetRows(rscount));
VARIANT (*pbstr)[5]=NULL;
saRetRS.AccessData((LPVOID*)&pbstr);
long lUBoundX;
long lUBoundY;
saRetRS.GetUBound(1,&lUBoundX);
saRetRS.GetUBound(2,&lUBoundY);
CString strNaShuiRenBianMa;
CString StrMingChen;
CString strDengJiZhuCeLeiXing;
int tmpFirstSheetEnd=0;
for(int i=0;i<CompanyNum&&
it__cListOfOneCompanyDBRows!=filteredLst->m_pSmartList->crend();
i++,++it__cListOfOneCompanyDBRows)//CompanyNum
{
::PostMessage(m_pDialogProgress->m_hWnd,MY_MACRO_WM_USER_THREAD_UPDATE_PROGRESS,i,CompanyNum);
strNaShuiRenBianMa=_T("");
int OneCompanyDataCount=(*it__cListOfOneCompanyDBRows)->m_pSmartList->size();
it__cOneDBRowOfCompany=
(*it__cListOfOneCompanyDBRows)->m_pSmartList->begin();
StrMingChen=(*it__cOneDBRowOfCompany)->NaShuiRenMingChen;
//CString Str
if(FindInMuLu(pbstr,lUBoundY,
(*it__cOneDBRowOfCompany)->NaShuiRenMingChen,
SheetName,strNaShuiRenBianMa)==FALSE)
{
BOOST_THROW_EXCEPTION(_cMyExceptionImpl(_T("建立sheet名称失败"),this));
}
SheetName=SheetNamePrefix+SheetName;
saRet.Clear();
saRet.Create(VT_VARIANT,2,numElements);
saRetComment.Clear();
saRetComment.Create(VT_BSTR,2,numElementsComment);
if(m_IsProduceBudLvl==TRUE||m_IsExcludedLateFee==TRUE)
{
FillCOleSafeArray_ProduceSetting(it__cOneDBRowOfCompany,
saRet,saRetComment,OneCompanyDataCount);
}
else
{
FillCOleSafeArray(it__cOneDBRowOfCompany,
saRet,saRetComment,OneCompanyDataCount);
}
CreateOneSheetXml(saRet,saRetComment,SheetName,
strNaShuiRenBianMa,StrMingChen,(*it__cListOfOneCompanyDBRows)->m_strMultZheCeLeiXing,
hStream,hSecStream,xmlInfoObj,i,isVLst);
}
saRetRS.UnaccessData();
TmpUTF8CStrCh=UnicodeToUtf8(xmlInfoObj.m_TmplCStrFileFooter);
TmpUTF8CStr=TmpUTF8CStrCh;
free(TmpUTF8CStrCh);
WriteFile(hStream,TmpUTF8CStr.GetBuffer(),
TmpUTF8CStr.GetLength(),&BytesWritten,NULL);
TmpUTF8CStr.ReleaseBuffer();
}catch(std::exception & exp )
{
exp.what();
return FALSE;
}
catch(_com_error &e)
{
dump_com_error(e);
return FALSE;
}
catch(...)
{
ShowMessageDialog(_T("线程异常类型4:CException"),_T("错误!"),this);
return FALSE;
}
return TRUE;
}
关于XmlContentInfo类:
struct XmlContentInfo
{
XmlContentInfo();
XmlElementInfo m_TmplWholeFile;
XmlElementInfo m_TmplWorkSheetElement;
XmlElementInfo m_TmplColumnElement;
XmlElementInfo m_TmplFirstRowElement;
XmlElementInfo m_TmplSecondRowElement;
XmlElementInfo m_TmplMiddleRowElement;
XmlElementInfo m_TmplSumRowElement;
XmlElementInfo m_TmplLeftRowElement;
XmlElementInfo m_TmplTableElement;
XmlElementInfo m_SecRwCellElement;
XmlElementInfo m_MidRwFirstCellElement;
XmlElementInfo m_MidRwSecondCellElement;
XmlElementInfo m_MidRwSecCelFirstDataElement;
XmlElementInfo m_MidRwSecCelCommentElement;
XmlElementInfo m_SmRwFirstCellElement;
XmlElementInfo m_SmRwSecondCellElement;
XmlElementInfo m_SmRwSecCelFirstDataElement;
XmlElementInfo m_FstRwFirstCellElement;
XmlElementInfo m_FstRwSecondCellElement;
XmlElementInfo m_FstRwThirdCellElement;
CString m_TmplCStrColumnArea;
CString m_TmplCStrFileHeader;
static const CString m_TmplCStrFileFooter;
static const CString CStrRowHeader;
static const CString CStrRowFooter;
CString m_TmplCStrSheetHeader;
CString m_TmplCStrOrignalSheetName;
CString m_TmplCStrSheetFooter;
CString m_TmplCStrSumRowFormula;
static const char m_UTF8Header[3];
CString m_CStrTableHeader;
CString m_CStrColumnIndexField;
};
#include "TemplateFileData.h"
const char XmlContentInfo::m_UTF8Header[3]={(char)0xEF,(char)0xBB,(char)0xBF};
const CString XmlContentInfo::m_TmplCStrFileFooter=_T("</Workbook>");
const CString XmlContentInfo::CStrRowHeader=_T("<Row ss:AutoFitHeight=\"0\">");
const CString XmlContentInfo::CStrRowFooter=_T("</Row>");
const CString TaiZhangTemplateStr=_T("<?xml version=\"1.0\"?>\
<?mso-application progid=\"Excel.Sheet\"?>\
<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"\
xmlns:o=\"urn:schemas-microsoft-com:office:office\"\
xmlns:x=\"urn:schemas-microsoft-com:office:excel\"\
xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\"\
xmlns:html=\"http://www.w3.org/TR/REC-html40\">\
<DocumentProperties xmlns=\"urn:schemas-microsoft-com:office:office\">\
<Author>XZG</Author>\
<LastAuthor>xxx</LastAuthor>\
<Created>2011-06-17T00:56:31Z</Created>\
<LastSaved>2014-07-05T09:09:42Z</LastSaved>\
<Company>阿盟地税直属局</Company>\
<Version>12.00</Version>\
</DocumentProperties>\
<ExcelWorkbook xmlns=\"urn:schemas-microsoft-com:office:excel\">\
<WindowHeight>7380</WindowHeight>\
<WindowWidth>15480</WindowWidth>\
<WindowTopX>1140</WindowTopX>\
<WindowTopY>645</WindowTopY>\
<ProtectStructure>False</ProtectStructure>\
<ProtectWindows>False</ProtectWindows>\
</ExcelWorkbook>\
<Styles>\
<Style ss:ID=\"Default\" ss:Name=\"Normal\">\
<Alignment ss:Vertical=\"Center\"/>\
<Borders/>\
<Font ss:FontName=\"宋体\" x:CharSet=\"134\" ss:Size=\"12\"/>\
<Interior/>\
<NumberFormat/>\
<Protection/>\
</Style>\
<Style ss:ID=\"s62\">\
<Protection ss:Protected=\"0\"/>\
</Style>\
<Style ss:ID=\"s64\">\
<Alignment ss:Horizontal=\"Center\" ss:Vertical=\"Center\"/>\
<Protection ss:Protected=\"0\"/>\
</Style>\
<Style ss:ID=\"s66\">\
<Alignment ss:Horizontal=\"Center\" ss:Vertical=\"Center\"/>\
<NumberFormat ss:Format=\"0\"/>\
<Protection ss:Protected=\"0\"/>\
</Style>\
<Style ss:ID=\"s68\">\
<Alignment ss:Vertical=\"Center\"/>\
<Font ss:FontName=\"宋体\" x:CharSet=\"134\" ss:Size=\"12\"/>\
<Protection ss:Protected=\"0\"/>\
</Style>\
<Style ss:ID=\"s69\">\
<Protection/>\
</Style>\
<Style ss:ID=\"s70\">\
<Font ss:FontName=\"宋体\" x:CharSet=\"134\" ss:Size=\"12\"/>\
<Protection ss:Protected=\"0\"/>\
</Style>\
</Styles>\
<Worksheet ss:Name=\"Sheet1\">\
<Table ss:ExpandedColumnCount=\"18\" ss:ExpandedRowCount=\"17\" x:FullColumns=\"1\"\
x:FullRows=\"1\" ss:StyleID=\"s62\" ss:DefaultColumnWidth=\"52.5\"\
ss:DefaultRowHeight=\"15.5625\">\
<Column ss:Index=\"2\" ss:StyleID=\"s62\" ss:AutoFitWidth=\"0\" ss:Width=\"75.75\"\
ss:Span=\"16\"/>\
<Row ss:AutoFitHeight=\"0\">\
<Cell ss:MergeAcross=\"5\" ss:StyleID=\"s64\"><Data ss:Type=\"String\">hhh</Data></Cell>\
<Cell ss:MergeAcross=\"5\" ss:StyleID=\"s66\"><Data ss:Type=\"String\">KKK</Data></Cell>\
<Cell ss:MergeAcross=\"3\" ss:StyleID=\"s68\"><Data ss:Type=\"String\">LLL</Data></Cell>\
</Row>\
<Row ss:AutoFitHeight=\"0\">\
<Cell><Data ss:Type=\"String\">月份</Data></Cell>\
</Row>\
<Row ss:AutoFitHeight=\"0\">\
<Cell><Data ss:Type=\"Number\">1</Data></Cell>\
<Cell ss:StyleID=\"s69\" ss:Formula=\"=x\"><Data ss:Type=\"Error\">#NAME?</Data><Comment><ss:Data\
xmlns=\"http://www.w3.org/TR/REC-html40\"><B><Font html:Face=\"Tahoma\"\
x:CharSet=\"134\" x:Family=\"Swiss\" html:Color=\"#000000\">sssss</Font></B></ss:Data></Comment></Cell>\
</Row>\
<Row ss:AutoFitHeight=\"0\">\
<Cell><Data ss:Type=\"String\">合计</Data></Cell>\
<Cell ss:StyleID=\"s69\" ss:Formula=\"=SUM(R[-1]C:R[1048564]C)\"><Data\
ss:Type=\"Error\">#NAME?</Data></Cell>\
</Row>\
<Row ss:Index=\"17\" ss:AutoFitHeight=\"0\">\
<Cell ss:Index=\"4\" ss:StyleID=\"s70\"><Data ss:Type=\"String\">此台帐不能反映抵扣税款情况,只能保证与当时的通用统计结果一致。个体挂企业名称的也不反映。包含滞纳金</Data></Cell>\
</Row>\
</Table>\
<WorksheetOptions xmlns=\"urn:schemas-microsoft-com:office:excel\">\
<Unsynced/>\
<Print>\
<ValidPrinterInfo/>\
<PaperSizeIndex>9</PaperSizeIndex>\
<HorizontalResolution>600</HorizontalResolution>\
<VerticalResolution>600</VerticalResolution>\
</Print>\
<Zoom>75</Zoom>\
<Selected/>\
<FreezePanes/>\
<FrozenNoSplit/>\
<SplitHorizontal>2</SplitHorizontal>\
<TopRowBottomPane>2</TopRowBottomPane>\
<SplitVertical>1</SplitVertical>\
<LeftColumnRightPane>1</LeftColumnRightPane>\
<ActivePane>0</ActivePane>\
<Panes>\
<Pane>\
<Number>3</Number>\
<ActiveRow>57</ActiveRow>\
<ActiveCol>7</ActiveCol>\
</Pane>\
<Pane>\
<Number>1</Number>\
<ActiveRow>57</ActiveRow>\
<ActiveCol>7</ActiveCol>\
</Pane>\
<Pane>\
<Number>2</Number>\
<ActiveRow>57</ActiveRow>\
<ActiveCol>7</ActiveCol>\
</Pane>\
<Pane>\
<Number>0</Number>\
<ActiveRow>1</ActiveRow>\
<RangeSelection>C2:C18</RangeSelection>\
</Pane>\
</Panes>\
<ProtectObjects>False</ProtectObjects>\
<ProtectScenarios>False</ProtectScenarios>\
<EnableSelection>UnlockedCells</EnableSelection>\
</WorksheetOptions>\
</Worksheet>\
</Workbook>\
");
关于编码转换:
#include "UTFConverter.h"
/* -------------------------------------------------------------
内码转换
------------------------------------------------------------- */
// 转换UCS4编码到UTF8编码
INT CUnicodeConverter::UCS4_To_UTF8( DWORD dwUCS4, BYTE* pbUTF8 )
{
const BYTE abPrefix[] = {0, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
const DWORD adwCodeUp[] = {
0x80, // U+00000000 ~ U+0000007F
0x800, // U+00000080 ~ U+000007FF
0x10000, // U+00000800 ~ U+0000FFFF
0x200000, // U+00010000 ~ U+001FFFFF
0x4000000, // U+00200000 ~ U+03FFFFFF
0x80000000 // U+04000000 ~ U+7FFFFFFF
};
INT i, iLen;
// 根据UCS4编码范围确定对应的UTF-8编码字节数
iLen = sizeof(adwCodeUp) / sizeof(DWORD);
for( i = 0; i < iLen; i++ )
{
if( dwUCS4 < adwCodeUp[i] )
{
break;
}
}
if( i == iLen )return 0; // 无效的UCS4编码
iLen = i + 1; // UTF-8编码字节数
if( pbUTF8 != NULL )
{ // 转换为UTF-8编码
for( ; i > 0; i-- )
{
pbUTF8[i] = static_cast<BYTE>((dwUCS4 & 0x3F) | 0x80);
dwUCS4 >>= 6;
}
pbUTF8[0] = static_cast<BYTE>(dwUCS4 | abPrefix[iLen - 1]);
}
return iLen;
}
// 转换UTF8编码到UCS4编码
INT CUnicodeConverter::UTF8_To_UCS4( const BYTE* pbUTF8, DWORD& dwUCS4 )
{
INT i, iLen;
BYTE b;
if( pbUTF8 == NULL )
{ // 参数错误
return 0;
}
b = *pbUTF8++;
if( b < 0x80 )
{
dwUCS4 = b;
return 1;
}
if( b < 0xC0 || b > 0xFD )
{ // 非法UTF8
return 0;
}
if( b < 0xE0 )
{
dwUCS4 = b & 0x1F;
iLen = 2;
}
else if( b < 0xF0 )
{
dwUCS4 = b & 0x0F;
iLen = 3;
}
else if( b < 0xF8 )
{
dwUCS4 = b & 7;
iLen = 4;
}
else if( b < 0xFC )
{
dwUCS4 = b & 3;
iLen = 5;
}
else
{
dwUCS4 = b & 1;
iLen = 6;
}
for( i = 1; i < iLen; i++ )
{
b = *pbUTF8++;
if( b < 0x80 || b > 0xBF )
{ // 非法UTF8
break;
}
dwUCS4 = (dwUCS4 << 6) + (b & 0x3F);
}
if( i < iLen )
{ // 非法UTF8
return 0;
}
else
{
return iLen;
}
}
// 转换UCS4编码到UCS2编码
INT CUnicodeConverter::UCS4_To_UTF16( DWORD dwUCS4, WORD* pwUTF16 )
{
if( dwUCS4 <= 0xFFFF )
{
if( pwUTF16 != NULL )
{
*pwUTF16 = static_cast<WORD>(dwUCS4);
}
return 1;
}
else if( dwUCS4 <= 0xEFFFF )
{
if( pwUTF16 != NULL )
{
pwUTF16[0] = static_cast<WORD>( 0xD800 + (dwUCS4 >> 10) - 0x40 ); // 高10位
pwUTF16[1] = static_cast<WORD>( 0xDC00 + (dwUCS4 & 0x03FF) ); // 低10位
}
return 2;
}
else
{
return 0;
}
}
// 转换UCS2编码到UCS4编码
INT CUnicodeConverter::UTF16_To_UCS4( const WORD* pwUTF16, DWORD& dwUCS4 )
{
WORD w1, w2;
if( pwUTF16 == NULL )
{ // 参数错误
return 0;
}
w1 = pwUTF16[0];
if( w1 >= 0xD800 && w1 <= 0xDFFF )
{ // 编码在替代区域(Surrogate Area)
if( w1 < 0xDC00 )
{
w2 = pwUTF16[1];
if( w2 >= 0xDC00 && w2 <= 0xDFFF )
{
dwUCS4 = (w2 & 0x03FF) + (((w1 & 0x03FF) + 0x40) << 10);
return 2;
}
}
return 0; // 非法UTF16编码
}
else
{
dwUCS4 = w1;
return 1;
}
}
// 转换UTF8字符串到UTF16字符串
INT CUnicodeConverter::UTF8Str_To_UTF16Str( const BYTE* pbszUTF8Str, WORD* pwszUTF16Str )
{
INT iNum, iLen;
DWORD dwUCS4;
if( pbszUTF8Str == NULL )
{ // 参数错误
return 0;
}
iNum = 0; // 统计有效字符个数
while( *pbszUTF8Str )
{ // UTF8编码转换为UCS4编码
iLen = UTF8_To_UCS4( pbszUTF8Str, dwUCS4 );
if( iLen == 0 )
{ // 非法的UTF8编码
return 0;
}
pbszUTF8Str += iLen;
// UCS4编码转换为UTF16编码
iLen = UCS4_To_UTF16( dwUCS4, pwszUTF16Str );
if( iLen == 0 )
{
return 0;
}
if( pwszUTF16Str != NULL )
{
pwszUTF16Str += iLen;
}
iNum += iLen;
}
if( pwszUTF16Str != NULL )
{
*pwszUTF16Str = 0; // 写入字符串结束标记
}
return iNum;
}
// 转换UTF16字符串到UTF8字符串
INT CUnicodeConverter::UTF16Str_To_UTF8Str( const WORD* pwszUTF16Str, BYTE* pbszUTF8Str )
{
INT iNum, iLen;
DWORD dwUCS4;
if( pwszUTF16Str == NULL )
{ // 参数错误
return 0;
}
iNum = 0;
while( *pwszUTF16Str )
{ // UTF16编码转换为UCS4编码
iLen = UTF16_To_UCS4( pwszUTF16Str, dwUCS4 );
if( iLen == 0 )
{ // 非法的UTF16编码
return 0;
}
pwszUTF16Str += iLen;
// UCS4编码转换为UTF8编码
iLen = UCS4_To_UTF8( dwUCS4, pbszUTF8Str );
if( iLen == 0 )
{
return 0;
}
if( pbszUTF8Str != NULL )
{
pbszUTF8Str += iLen;
}
iNum += iLen;
}
if( pbszUTF8Str != NULL )
{
*pbszUTF8Str = 0; // 写入字符串结束标记
}
return iNum;
}
/* -------------------------------------------------------------
C文件写入操作
------------------------------------------------------------- */
// 向文件中输出UTF8编码
UINT CUnicodeConverter::Print_UTF8_By_UCS4( FILE* out, DWORD dwUCS4 )
{
INT iLen;
BYTE abUTF8[8];
if( out == NULL )
{
return 0;
}
iLen = UCS4_To_UTF8( dwUCS4, abUTF8 );
if( iLen == 0 )return 0;
fwrite( abUTF8, 1, iLen, out );
return iLen;
}
// 向文件中输出UTF16编码
UINT CUnicodeConverter::Print_UTF16_By_UCS4( FILE* out, DWORD dwUCS4, BOOL isBigEndian )
{
INT i, iLen;
WORD wCode, awUTF16[2];
if( out == NULL )
{
return 0;
}
iLen = UCS4_To_UTF16( dwUCS4, awUTF16 );
if( iLen == 0 )return 0;
for( i = 0; i < iLen; i++ )
{
wCode = awUTF16[i];
if( isBigEndian )
{
fputc( wCode >> 8, out ); // 输出高位
fputc( wCode & 0xFF, out ); // 输出低位
}
else
{
fputc( wCode & 0xFF, out ); // 输出低位
fputc( wCode >> 8, out ); // 输出高位
}
}
return (iLen << 1);
}
// 将UTF16字符串以UTF8编码输出到文件中
UINT CUnicodeConverter::Print_UTF8Str_By_UTF16Str( FILE* out, const WORD* pwszUTF16Str )
{
INT iCount, iLen;
DWORD dwUCS4;
if( (out == NULL) || (pwszUTF16Str == NULL) )
{
return 0;
}
iCount = 0;
while( *pwszUTF16Str )
{ // 将UTF16编码转换成UCS4编码
iLen = UTF16_To_UCS4( pwszUTF16Str, dwUCS4 );
if( iLen == 0 )
{
break;
}
pwszUTF16Str += iLen;
// 向文件中输出UTF8编码
iCount += Print_UTF8_By_UCS4( out, dwUCS4 );
}
return iCount; // 输出的字节数
}
// 将UTF8字符串以UTF16编码输出到文件中
UINT CUnicodeConverter::Print_UTF16Str_By_UTF8Str( FILE* out, const BYTE* pbszUTF8Str, BOOL isBigEndian )
{
INT iCount, iLen;
DWORD dwUCS4;
if( (out == NULL) || (pbszUTF8Str == NULL) )
{
return 0;
}
iCount = 0;
while( *pbszUTF8Str )
{ // 将UTF16编码转换成UCS4编码
iLen = UTF8_To_UCS4( pbszUTF8Str, dwUCS4 );
if( iLen == 0 )
{
break;
}
pbszUTF8Str += iLen;
// 向文件中输出UTF8编码
iCount += Print_UTF16_By_UCS4( out, dwUCS4, isBigEndian );
}
return iCount; // 输出的字节数
}
// 向文件中输出UTF8字节序标记
UINT CUnicodeConverter::Print_UTF8_BOM( FILE* out )
{
if( out == NULL )
{
return 0;
}
fputc( 0xEF, out );
fputc( 0xBB, out );
fputc( 0xBF, out );
return 3;
}
// 向文件中输出UTF16字节序标记
UINT CUnicodeConverter::Print_UTF16_BOM( FILE* out, BOOL isBigEndian )
{
if( out == NULL )
{
return 0;
}
if( isBigEndian )
{
fputc( 0xFE, out );
fputc( 0xFF, out );
}
else
{
fputc( 0xFF, out );
fputc( 0xFE, out );
}
return 2;
}
/* -------------------------------------------------------------
C++流输出操作
------------------------------------------------------------- */
// 向流中输出UTF8编码
UINT CUnicodeConverter::Print_UTF8_By_UCS4( ostream& os, DWORD dwUCS4 )
{
INT iLen;
BYTE abUTF8[8];
if( !os )return 0;
iLen = UCS4_To_UTF8( dwUCS4, abUTF8 );
if( iLen == 0 )return 0;
os.write( reinterpret_cast<CHAR*>(abUTF8), iLen );
return iLen;
}
// 向流中输出UTF16编码
UINT CUnicodeConverter::Print_UTF16_By_UCS4( ostream& os, DWORD dwUCS4, BOOL isBigEndian )
{
INT i, iLen;
WORD wCode, awUTF16[2];
if( !os )return 0;
iLen = UCS4_To_UTF16( dwUCS4, awUTF16 );
if( iLen == 0 )return 0;
for( i = 0; i < iLen; i++ )
{
wCode = awUTF16[i];
if( isBigEndian )
{
os.put( wCode >> 8 ); // 输出高位
os.put( wCode & 0xFF ); // 输出低位
}
else
{
os.put( wCode & 0xFF ); // 输出低位
os.put( wCode >> 8 ); // 输出高位
}
}
return (iLen << 1);
}
// 将UTF16字符串以UTF8编码输出到流中
UINT CUnicodeConverter::Print_UTF8Str_By_UTF16Str( ostream& os, const WORD* pwszUTF16Str )
{
INT iCount, iLen;
DWORD dwUCS4;
if( !os || (pwszUTF16Str == NULL) )return 0;
iCount = 0;
while( *pwszUTF16Str )
{ // 将UTF16编码转换成UCS4编码
iLen = UTF16_To_UCS4( pwszUTF16Str, dwUCS4 );
if( iLen == 0 )
{
break;
}
pwszUTF16Str += iLen;
// 向流中输出UTF8编码
iCount += Print_UTF8_By_UCS4( os, dwUCS4 );
}
return iCount; // 输出的字节数
}
// 将UTF8字符串以UTF16编码输出到流中
UINT CUnicodeConverter::Print_UTF16Str_By_UTF8Str( ostream& os, const BYTE* pbszUTF8Str, BOOL isBigEndian )
{
INT iCount, iLen;
DWORD dwUCS4;
if( !os || (pbszUTF8Str == NULL) )return 0;
iCount = 0;
while( *pbszUTF8Str )
{ // 将UTF16编码转换成UCS4编码
iLen = UTF8_To_UCS4( pbszUTF8Str, dwUCS4 );
if( iLen == 0 )
{
break;
}
pbszUTF8Str += iLen;
// 向流中输出UTF8编码
iCount += Print_UTF16_By_UCS4( os, dwUCS4, isBigEndian );
}
return iCount; // 输出的字节数
}
// 向流中输出UTF8字节序标记
UINT CUnicodeConverter::Print_UTF8_BOM( ostream& os )
{
if( !os )return 0;
os.put( 0xEF );
os.put( 0xBB );
os.put( 0xBF );
return 3;
}
// 向流中输出UTF16字节序标记
UINT CUnicodeConverter::Print_UTF16_BOM( ostream& os, BOOL isBigEndian )
{
if( !os )return 0;
if( isBigEndian )
{
os.put( 0xFE );
os.put( 0xFF );
}
else
{
os.put( 0xFF );
os.put( 0xFE );
}
return 2;
}
/* ------------------------------
END
------------------------------ */
关于最后的编码转换,本人因为该程序开发过去不少时间,编码转换到底用不用的上,不好说,一并贴出来,供大家参考。