VC++6.0操作excel2007文件封装类CExcelServer

 

转自:http://blog.chinaunix.net/uid-23089249-id-3605764.html

 


参考文章:
1、VC操作Excel文件编程相关内容总结
2、VC++导出数据到Excel
3、VSTO学习笔记(二)Excel对象模型

利用VC操作Excel的方法至少有两种:
1、利用ODBC把Excel文件当成数据库文件,来进行读、写、修改等操作。网上有人编写了CSpreadSheet类,提供支持。
2、利用OLE Automation方法,将Excel当成组件服务器,利用VBA。

本文选择了第2中方式。要利用OLE Automation实现对Excel进行操作,必须与Excel对象模型提供的对象进行交互。Excel提供了数百个可能需要与之交互的对象,下面先了解一下编程中常用到的几个对象。

1) Application 对象:代表整个 Microsoft Excel 应用程序。
2) Workbook 对象:代表一个 Microsoft Excel 工作簿,即Excel文件。
3) Workbooks 对象:包含 Microsoft Excel 中当前打开的所有 Workbook 对象。
4) Worksheet 对象:代表一个工作表。一个工作簿中可以包括多个工作表。
5) Worksheets 对象:代表指定或活动工作簿中所有 Worksheet 对象的集合。
6) Range 对象:代表某一单元格、某一行、某一列、某一选定区域(该区域可包含一个或若干连续单元格区域)。Range对象是Excel操作的重点,对于数据插入、修改、删除都要通过它来实现,Range所表示等同于我们在实际编辑Excel文件时,用鼠标在表单中选择中的区域,选中之后再对其进行单元格修改、删除、合并、设置宽、高、颜色等操作。
7) Chart对象:代表工作簿中的图表。此图表既可以是嵌入的图表(包含在ChartObject对象中),也可以是单独的图表工作表。
8) Charts对象:代表指定或活动工作簿中所有图表工作表的集合。
9) Sheets 对象:代表指定或活动工作簿中所有工作表(可以是Chart对象或者WorkSheet对象)的集合。
10) Font对象:用于设置Range选中的单元格字体格式和颜色。
11) Interior对象:用于设置Range选中的单元格背景格式和颜色。
12) Borders对象:用于设置Range选中的单元格的边框。

其他对象可到msdn去了解:http://msdn.microsoft.com/zh-cn/library/office/ff194068.aspx

调用excel对象方法时,常常会用到一些枚举变量,可以到msdn中查找相关值:http://msdn.microsoft.com/zh-cn/library/office/ff838815.aspx

在操作Excel之前,必须向工程中添加Excel对象,其步骤是: 选择Menu --> View --> ClassWizard,打开ClassWizard 窗口, 选择Add Class -->From a type library,若系统中安装的是Office2000,则在Office 安装目录选择Excel.OLB,如果安装的是Office2003或2007,则选择Excel.exe;然后根据需要选择添加的类(如果要使用下面的CExcelServer封装类,必须加入_Application,Workbooks,_Workbook ,Worksheets,_Work2sheet,Range,Font,Interior,Borders等),向导会在工程中自动生成加入了这些类的Excel.h和Excel.cpp两个文件。在要使用这些导入的类时加入#include "Excel.h"即可。

CExcelServer类头文件

#if !defined(AFX_EXCELSERVER_H__7495C273_745B_4F87_A729_D057CAA8D2A9__INCLUDED_)
 
#define AFX_EXCELSERVER_H__7495C273_745B_4F87_A729_D057CAA8D2A9__INCLUDED_


#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// ExcelServer.h : header file
//

#include <afxcoll.h>
#include "excel.h"

 
#define InfoMessageBox(strMsg) \
AfxMessageBox(strMsg, MB_OK | MB_ICONINFORMATION)
#define DebugMessageBox(strMsg) \
AfxMessageBox(strMsg, MB_OK | MB_ICONINFORMATION)
#define WarningMessageBox(strMsg) \
AfxMessageBox(strMsg, MB_OK | MB_ICONWARNING)
#define ErrorMessageBox(strMsg) \
AfxMessageBox(strMsg, MB_OK | MB_ICONERROR)
 

//Excel文件格式
//http://msdn.microsoft.com/zh-cn/library/office/ff198017.aspx
typedef enum
{
    xlCSV                = 6,        //csv
    xlTextWindows        = 20,        //Windows 文本
    xlTextMSDOS          = 21,        //MSDOS 文本
    xlUnicodeText        = 42,        //Unicode 文本
    xlExcel9795          = 43,        //Excel9795
    xlWorkbookNormal     = -4143,    //常规工作簿
    xlExcel12            = 50,        //Excel 12
    xlWorkbookDefault    = 51,        //默认工作簿
} XlFileFormat;

//水平对齐方式
//http://msdn.microsoft.com/zh-cn/library/office/ff840772.aspx
typedef enum
{
    xlHAlignCenter                   = -4108,    //居中对齐
    xlHAlignCenterAcrossSelection    = 7,        //跨列居中
    xlHAlignDistributed              = -4117,    //分散对齐
    xlHAlignFill                     = 5,        //填充
    xlHAlignGeneral                  = 1,        //按数据类型对齐
    xlHAlignJustify                  = -4130,    //两端对齐
    xlHAlignLeft                     = -4131,    //左对齐
    xlHAlignRight                    = -4152,    //右对齐
} XlHAlign;

//垂直对齐方式
//http://msdn.microsoft.com/zh-cn/library/office/ff835305.aspx
typedef enum
{
    xlVAlignBottom         = -4107,        //靠下 
    xlVAlignCenter         = -4108,        //居中对齐 
    xlVAlignDistributed    = -4117,        //分散对齐 
    xlVAlignJustify        = -4130,        //两端对齐 
    xlVAlignTop            = -4160,        //靠上 
} XlVAlign;

//插入时单元格的移动方向
//http://msdn.microsoft.com/zh-cn/library/office/ff837618.aspx
typedef enum
{
    xlShiftDown        = -4121,        //向下移动单元格
    xlShiftToRight     = -4161,        //向右移动单元格
} XlInsertShiftDirection;

//边框的线条样式
//http://msdn.microsoft.com/zh-cn/library/office/ff821622.aspx
typedef enum
{
    xlContinuous    = 1,        //实线
    xlDash          = -4115,    //虚线
    xlDashDot       = 4,        //点划相间线
    xlDashDotDot    = 5,        //划线后跟两个点
    xlDot           = -4118,    //点式线
    xlDouble        = -4119,    //双线
    xlLineStyleNone = -4142,    //无线条
    xlSlantDashDot  = 13,        //倾斜的划线
} XlLineStyle;

//边框的粗细
//http://msdn.microsoft.com/zh-cn/library/office/ff197515.aspx
typedef enum
{
    xlHairline        = 1,        //细线(最细的边框)
    xlMedium          = -4138,    //中等
    xlThick           = 4,        //粗(最宽的边框)
    xlThin            = 2,        //细
} XlBorderWeight;

/
// CExcelServer window create by lingdxuyan

class CExcelServer : public CWnd
{
// Construction
public:
     CExcelServer();

// Attributes
private:
     CString            m_strExcelFile;
     CString            m_strWorkSheet;

     _Application    m_oExcelApp;    // Excel程序
     _Worksheet        m_oWorkSheet;    // 工作表
     _Workbook        m_oWorkBook;    // 工作簿
     Workbooks        m_oWorkBooks;    // 工作簿集合
     Worksheets        m_oWorkSheets;    // 工作表集合
     Range            m_oCurrRange;    // 使用区域

// Operations
private:
    //创建Excel服务
    BOOL CreateExcelServer();
    //销毁Excel服务
    void DestroyExcelServer();

public:
    //打开指定工作薄
    BOOL OpenWorkBook(CString strExcelFile);

    //在已打开的工作薄中,打开指定工作薄
    BOOL OpenWorkSheet(CString strWorkSheet);
    //打开指定工作薄和工作表
    BOOL OpenWorkSheet(CString strExcelFile, CString strWorkSheet);
    //关闭当前打开的工作薄
    void CloseWorkBook();
    //关闭工作表
    void CloseWorkSheet();
    //保存工作薄
    void WorkBookSave();
    //将工作薄另存为指定格式
    BOOL WorkBookSaveAs(CString strSaveAsFile, XlFileFormat fileFormat);
    //将工作表另存为指定格式
    void WorkSheetSaveAs(CString strSaveAsFile, XlFileFormat fileFormat);
    //获取当前工作表已使用的行数
    long GetUsedRowsCount();
    //获取当前工作表已使用的列数
    long GetUsedColumnsCount();
    //获取当前工作表中一行数据
    BOOL GetRowString(UINT nRow, CStringArray &array);
    //在指定行插入数据
    void InsertRow(UINT nRow, CStringArray &array);
    //设置指定单元格颜色
    void SetRangeBackgroundColor(CString strStart, CString strEnd, long nColorIndex);
    //设置单元格边框
    void SetRangeBorders(CString strStart, CString strEnd, XlLineStyle lineStyle, 
                                 XlBorderWeight borderWeight);
    //设置单元格外边框
    void SetRangeBorderAround(CString strStart, CString strEnd, XlLineStyle lineStyle, 
                                 XlBorderWeight borderWeight);
    //设置所有单元格的水平对齐和垂直对齐
    void SetAlignment(CString strStart, CString strEnd, XlHAlign hAlign, XlVAlign vAlign);

// Overrides
     // ClassWizard generated virtual function overrides
     //{{AFX_VIRTUAL(CExcelServer)
     //}}AFX_VIRTUAL

// Implementation
public:
     virtual ~CExcelServer();

     // Generated message map functions
protected:
     //{{AFX_MSG(CExcelServer)
         // NOTE - the ClassWizard will add and remove member functions here.
     //}}AFX_MSG
     DECLARE_MESSAGE_MAP()
};

/

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_EXCELSERVER_H__7495C273_745B_4F87_A729_D057CAA8D2A9__INCLUDED_) 


CExcelServer类cpp文件

// ExcelServer.cpp : implementation file
//

#include "stdafx.h"
#include "ExcelServer.h"
#include <afxtempl.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// CExcelServer

CExcelServer::CExcelServer()
{
     m_strExcelFile = _T("");
     m_strWorkSheet = _T("");
     CreateExcelServer();
}

CExcelServer::~CExcelServer()
{
     CloseWorkBook();
     DestroyExcelServer();
}


BEGIN_MESSAGE_MAP(CExcelServer, CWnd)
     //{{AFX_MSG_MAP(CExcelServer)
         // NOTE - the ClassWizard will add and remove mapping macros here.
     //}}AFX_MSG_MAP
 END_MESSAGE_MAP()


/
// CExcelServer message handlers

BOOL CExcelServer::CreateExcelServer()
{
    if (0 != CoInitialize(NULL))
    {
        ErrorMessageBox(_T("初始化COM支持库失败!"));
        exit(1);
    }

    //创建Excel服务
    if (!m_oExcelApp.CreateDispatch(_T("Excel.Application"), NULL)) 
    {
        ErrorMessageBox(_T("创建Excel服务失败!")); 
        return FALSE; 
    }

    //设置为显示
    m_oExcelApp.SetVisible(FALSE);

    return TRUE;
}

void CExcelServer::DestroyExcelServer()
{
     m_oExcelApp.ReleaseDispatch();
     m_oExcelApp.Quit(); // 这条语句是推出Excel程序,任务管理器中的EXCEL进程会自动结束。
}

BOOL CExcelServer::OpenWorkBook(CString strExcelFile)
{
     LPDISPATCH lpDisp = NULL;
     COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); 

     CloseWorkBook();
     m_oWorkBooks.AttachDispatch(m_oExcelApp.GetWorkbooks(), TRUE); //没有这条语句,下面打开文件返回失败。

    // 打开文件
    lpDisp = m_oWorkBooks.Open(strExcelFile, 
                  covOptional, 
                  covOptional,
                  covOptional,
                  covOptional,
                  covOptional,
                  covOptional,
                  covOptional,
                  covOptional,
                  covOptional,
                  covOptional,
                  covOptional,
                  covOptional,
                  covOptional,
                  covOptional );
     // 获得活动的WorkBook( 工作簿 )
     m_oWorkBook.AttachDispatch(lpDisp, TRUE);


     // 获得活动的WorkSheet( 工作表 )
//    m_oWorkSheet.AttachDispatch(m_oWorkBook.GetActiveSheet(), TRUE);


     m_strExcelFile = strExcelFile;
     return TRUE;
}

void CExcelServer::CloseWorkBook()
{
     COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
     
     if (!m_strExcelFile.IsEmpty())
     {
         // 关闭
        m_oWorkBook.SetSaved(TRUE); // 将Workbook的保存状态设置为已保存,即不让系统提示是否人工保存
        m_oWorkBook.Close(covOptional, COleVariant(m_strExcelFile), covOptional);
        m_oWorkBooks.Close();
         // 释放
        m_oWorkBook.ReleaseDispatch();
        m_oWorkBooks.ReleaseDispatch();
     }

     m_strExcelFile = _T("");

     CloseWorkSheet();
}

BOOL CExcelServer::OpenWorkSheet(CString strWorkSheet)
{
     CString strMsg;
     long i;

     CloseWorkSheet();

     // 打开工作表集,查找工作表strSheet
     m_oWorkSheets.AttachDispatch( m_oWorkBook.GetWorksheets(), TRUE );
     long lSheetNUM = m_oWorkSheets.GetCount();
     for (i=1; i<=lSheetNUM; i++) 
     { 
         m_oWorkSheet.AttachDispatch( m_oWorkSheets.GetItem(COleVariant((short)i)), TRUE );
         if (strWorkSheet == m_oWorkSheet.GetName())
             break;
     } 

     if (i > lSheetNUM)
     {
         strMsg.Format(_T("在%s中找不到名为%s的表"), m_strExcelFile, strWorkSheet);
         WarningMessageBox(strMsg);
         return FALSE;
     }
#ifdef _DEBUG
     else
     {
         strMsg.Format(_T("%s是%s第%d个表"), strWorkSheet, m_strExcelFile, i);
         DebugMessageBox(strMsg);
     }
#endif

     m_strWorkSheet = strWorkSheet;
     return TRUE;
}

BOOL CExcelServer::OpenWorkSheet(CString strExcelFile, CString strWorkSheet)
{
     if (!OpenWorkBook(strExcelFile))
         return FALSE;

     return OpenWorkSheet(strWorkSheet);
}

void CExcelServer::CloseWorkSheet()
{
     if (!m_strWorkSheet.IsEmpty())
     {
         m_oCurrRange.ReleaseDispatch();
         m_oWorkSheet.ReleaseDispatch();
         m_oWorkSheets.ReleaseDispatch();
     }

     m_strWorkSheet = _T("");
}

long CExcelServer::GetUsedRowsCount()
{
     // 获得使用的区域Range( 区域 )
     m_oCurrRange.AttachDispatch(m_oWorkSheet.GetUsedRange(), TRUE);

     // 获得使用的行数
     m_oCurrRange.AttachDispatch(m_oCurrRange.GetRows(), TRUE);
     return m_oCurrRange.GetCount();
}

BOOL CExcelServer::GetRowString(UINT nRow, CStringArray &array)
{ 
     Range oCurCell;
     CString strMsg;

     // 获得使用的列数
     long lUsedColumnNum = GetUsedColumnsCount();
     
     COleVariant covRow((long)nRow);
     CString strHeader;

     // 遍历列头
#ifdef _DEBUG
     strMsg.Format(_T("row %d:"), nRow);
#endif
     m_oCurrRange.AttachDispatch(m_oWorkSheet.GetUsedRange(), TRUE);
     for (long i=1; i<=lUsedColumnNum; i++)
     {
         if (0 != nRow)
         {
             //获取单元格数据
            oCurCell.AttachDispatch(m_oCurrRange.GetItem(covRow, COleVariant(i)).pdispVal, TRUE);
             strHeader = (oCurCell.GetText()).bstrVal;
         }

         //保存单元格数据
        array.Add(strHeader);
#ifdef _DEBUG
         strMsg += _T(" ") + strHeader;
#endif
     }

#ifdef _DEBUG    
     strHeader.Format(_T("size%d"), array.GetSize());
     strMsg += _T(" ") + strHeader;
     DebugMessageBox(strMsg);
#endif

     return TRUE;    
}

long CExcelServer::GetUsedColumnsCount()
{
     // 获得使用的区域Range( 区域 )
     m_oCurrRange.AttachDispatch(m_oWorkSheet.GetUsedRange(), TRUE);

     // 获得使用的列数
     m_oCurrRange.AttachDispatch( m_oCurrRange.GetColumns(), TRUE );
     return m_oCurrRange.GetCount();
}

void CExcelServer::InsertRow(UINT nRow, CStringArray &array)
{
     COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); 
     long size = array.GetSize();
     CString strCell, strData;
     char cColumn = 'A';
     Font oFont;

     if (nRow < 1)
     {
         WarningMessageBox(_T("%s: 行号必须大于0"));
         return;
     }

#ifdef _DEBUG
     CString strMsg;
     strMsg.Format(_T("row %d:"), nRow);
#endif

     for (long i=1; i<=size; i++)
     {
         //获取每1列第1个单元格
         strCell.Format("%c%d", cColumn++, nRow);
         m_oCurrRange.AttachDispatch(m_oWorkSheet.GetRange(COleVariant(strCell), 
             covOptional), TRUE);

         //当前位置插入单元格
         m_oCurrRange.Insert(COleVariant((short)xlShiftDown), covOptional);
         //设置单元格内容
         m_oCurrRange.AttachDispatch(m_oWorkSheet.GetRange(COleVariant(strCell), 
             covOptional), TRUE);
         strData = array.GetAt(i - 1);
         m_oCurrRange.SetValue2(COleVariant(strData));
#ifdef _DEBUG
         strMsg += _T(" ") + strData;
#endif
         //设置单元格字体加粗
         oFont.AttachDispatch(m_oCurrRange.GetFont(), TRUE);
         oFont.SetBold(COleVariant((short)TRUE));

         //自动列宽
         m_oCurrRange.AttachDispatch(m_oCurrRange.GetEntireColumn(), TRUE);
         m_oCurrRange.AutoFit();
     }

#ifdef _DEBUG
     DebugMessageBox(strMsg);
#endif

     oFont.ReleaseDispatch();
}

void CExcelServer::SetRangeBackgroundColor(CString strStart, CString strEnd, long nColorIndex)
{
     Interior oInterior; 

     //获取单元格区域
     m_oCurrRange.AttachDispatch(m_oWorkSheet.GetRange(COleVariant(strStart), 
         COleVariant(strEnd)), TRUE);

     //设置单元格背景色
     oInterior.AttachDispatch(m_oCurrRange.GetInterior(), TRUE); 
     oInterior.SetColorIndex(COleVariant(nColorIndex));

     oInterior.ReleaseDispatch();
}

void CExcelServer::SetRangeBorders(CString strStart, CString strEnd, 
                     XlLineStyle lineStyle, XlBorderWeight borderWeight)
{
     m_oCurrRange.AttachDispatch(m_oWorkSheet.GetRange(COleVariant(strStart), 
         COleVariant(strEnd)), TRUE);

     // 设置区域内所有单元格的边框 
     Borders oBorders; 
     oBorders.AttachDispatch(m_oCurrRange.GetBorders(), TRUE); 
     oBorders.SetColorIndex(COleVariant((long)1));            // 线的颜色(-4105为自动, 1为黑色) 
     oBorders.SetLineStyle(COleVariant((long)lineStyle)); 
     oBorders.SetWeight(COleVariant((long)borderWeight)); 
     oBorders.ReleaseDispatch();
}

void CExcelServer::SetRangeBorderAround(CString strStart, CString strEnd, 
                     XlLineStyle lineStyle, XlBorderWeight borderWeight)
{
     COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); 

     m_oCurrRange.AttachDispatch(m_oWorkSheet.GetRange(COleVariant(strStart), 
         COleVariant(strEnd)), TRUE);

     //设置外边框
     //线的颜色(-4105为自动, 1为黑色) 
     m_oCurrRange.BorderAround(COleVariant((long)lineStyle), borderWeight, 1, covOptional);
}

void CExcelServer::SetAlignment(CString strStart, CString strEnd, XlHAlign hAlign, XlVAlign vAlign)
{
     // 获得使用的区域Range( 区域 )
     m_oCurrRange.AttachDispatch(m_oWorkSheet.GetRange(COleVariant(strStart), 
         COleVariant(strEnd)), TRUE);
     // 设置水平对齐
     m_oCurrRange.SetHorizontalAlignment(COleVariant((short)hAlign));
     // 设置垂直对齐
     m_oCurrRange.SetVerticalAlignment(COleVariant((short)vAlign));    
}

BOOL CExcelServer::WorkBookSaveAs(CString strSaveAsFile, XlFileFormat fileFormat)
{
     COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); 
     CString strMsg;

#ifdef _DEBUG
     strMsg.Format(_T("excel %s save as %s"), 
         m_strExcelFile, strSaveAsFile);
     DebugMessageBox(strMsg);
#endif

     // 删除strSaveAsFile文件,以免excel另存为strSaveAsFile,磁盘中已存在同名文件
    ::DeleteFile(strSaveAsFile);

     // excel另存为strSaveAsFile
     m_oWorkBook.SaveAs(COleVariant(strSaveAsFile),COleVariant((short)fileFormat),covOptional,
                             covOptional,covOptional,covOptional,0,
                             covOptional,covOptional,covOptional,covOptional,covOptional); 

     return TRUE;    
}

void CExcelServer::WorkSheetSaveAs(CString strSaveAsFile, XlFileFormat fileFormat)
{
     COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); 
     CString strMsg;

#ifdef _DEBUG
     strMsg.Format(_T("excel %s sheet %s save as %s"), 
         m_strExcelFile, m_oWorkSheet.GetName(), strSaveAsFile);
     DebugMessageBox(strMsg);
#endif

     // 删除strSaveAsFile文件,以免excel另存为strSaveAsFile文件,磁盘中已存在同名文件
    ::DeleteFile(strSaveAsFile);

     // excel另存为strSaveAsFile
     m_oWorkSheet.SaveAs(strSaveAsFile,COleVariant((short)fileFormat),covOptional,
                             covOptional,covOptional,covOptional,
                             covOptional,covOptional,covOptional,covOptional); 
}

void CExcelServer::WorkBookSave()
{
     m_oWorkBook.Save();
     m_oWorkBook.SetSaved(TRUE); // 将Workbook的保存状态设置为已保存
} 


一个例子

先定义一个CExcelServer对象
2.CExcelServer     m_oExcelServer;    // Excel服务
 

     //打开xls文件
     m_oExcelServer.OpenWorkSheet(strExcelFile, m_strWorkSheet);
     //插入列头
     m_oExcelServer.InsertRow(1, m_arrayHeaders);

     //设置单元格边框和背景颜色
     CString strStartCell, strEndCell;
     long lUsedRowsNum = m_oExcelServer.GetUsedRowsCount();
     long lUsedColumnsNum = m_oExcelServer.GetUsedColumnsCount();
     strStartCell = "A1";
     strEndCell.Format("%c%d", 'A' + lUsedColumnsNum - 1, lUsedRowsNum);
     m_oExcelServer.SetRangeBorders(strStartCell, strEndCell, xlContinuous, xlThin);
     m_oExcelServer.SetRangeBorderAround(strStartCell, strEndCell, xlDouble, xlThin);
     m_oExcelServer.SetRangeBackgroundColor(strStartCell, strEndCell, 34);

     //设置单元格均为水平居中,垂直居中
     strStartCell.Format("A1");
     strEndCell.Format("%c%d", 'A' + lUsedColumnsNum - 1, lUsedRowsNum);
     m_oExcelServer.SetAlignment(strStartCell, strEndCell, xlHAlignCenter, xlVAlignCenter);

     //保存并关闭Excel文件
     m_oExcelServer.WorkBookSave();
     m_oExcelServer.CloseWorkBook(); 


CExcelServer类,只在VC++6.0、excel2007测试过!

 

原文地址:VC++6.0操作excel2007文件封装类CExcelServer    出自http://blog.chinaunix.net/uid/23089249.html

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值