关于以前excel内存打开操作函数的使用说明。

为方便读者使用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
------------------------------ */

关于最后的编码转换,本人因为该程序开发过去不少时间,编码转换到底用不用的上,不好说,一并贴出来,供大家参考。

猜你喜欢

转载自blog.csdn.net/tom_xuzg/article/details/82681961