Visual C++基础 - 使用OLE/COM操作Excel类

前言

工作经常遇到的需求之一,将数据保存至Excel中,然后对Excel中的数据进行一系列操作,本篇文章简单记录这个个过程。

本闻主要实现Excel的读写等一些基本操作,依赖于OLE/COM的Excel库实现,需要先对这些接口进行导入。接口主要是_Application、Workbooks、_Workbook、Worksheets、_Worksheet、Range、Interior、Cfond 类

部分接口说明如图下:

Visual C++基础 - 使用OLE/COM操作Excel类_第1张图片

第一部分:导入excel库

Visual C++基础 - 使用OLE/COM操作Excel类_第2张图片

可以通过注册表或者文件的形式导入,注册表打开如果找不到对应的库,可以选择用文件,用everything全局搜索Excel.exe。在位置处搜索到该exe所在路径即可。

Visual C++基础 - 使用OLE/COM操作Excel类_第3张图片

 需要导入的接口如下图:

Visual C++基础 - 使用OLE/COM操作Excel类_第4张图片

点击添加之后,进入各个头文件中注释掉 “#import "C:\\Program Files\\Microsoft Office\\root\\Office16\\EXCEL.EXE" no_namespace”这句话,VC的特性,不需要再次import。

另外如果出现变量名重定义的话,可以对其做一个修改。具体修改方式可以自行百度,不太重要。

Visual C++基础 - 使用OLE/COM操作Excel类_第5张图片

至此接口就添加完毕,include对应的.h之后就可以直接对表格内进行读写操作了。

Visual C++基础 - 使用OLE/COM操作Excel类_第6张图片

第二部分:操作Excel

 1、初始化变量和Excel库:

Visual C++基础 - 使用OLE/COM操作Excel类_第7张图片

// 初始化Excel库
bool CExcel_TestDlg::InitExcel()
{
	HRESULT ht;
	ht = ::CoInitialize(NULL);
	if (ht == E_INVALIDARG)
	{
		MessageBox(_T("初始化COM失败"));
	}

	//创建Execel(启动Excel)
	if (!m_App.CreateDispatch(_T("Excel.application"), nullptr))
	{
		MessageBox(_T("Error!Creat Excel Application Sever Fail!"));
		exit(1);
		return FALSE;
	}

	m_App.put_Visible(FALSE);//是否显示EXCEL
	m_App.put_DisplayFullScreen(FALSE);//设置全屏显示
	m_App.put_DisplayAlerts(FALSE);//屏蔽警告
	return TRUE;
}

2、生成一个表格

BOOL CExcel_TestDlg::CreatNewExcel(CString strPath)
{
	//InitExcel();

	m_Books = m_App.get_Workbooks();

	try
	{
		m_WorkBook = m_Books.Add(_variant_t(strPath));//打开EXCEL文件
	}
	catch (CException* e)
	{
		m_WorkBook = m_Books.Add(vtMissing);//找不到就新建一个
	}

	m_OpenFileName = strPath;

	m_WorkSheet = m_WorkBook.get_ActiveSheet();//获取当前工作表


											   
	//保存  定义变量//
	COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);

	m_WorkBook.SaveAs(COleVariant(strPath),
		covOptional,
		covOptional,
		covOptional,
		covOptional,
		covOptional,
		0,
		covOptional,
		covOptional,
		covOptional,
		covOptional,
		covOptional,
		covOptional);
	//释放资源 - 演示用,如果需要对其操作,当然是先不用关闭了
	close();
	//关闭应用
	m_App.Quit();
	m_App.ReleaseDispatch();
	m_App = nullptr;

	return TRUE;
}

void CExcel_TestDlg::close(BOOL ifSave /*= FALSE*/)
{
	COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
	//如果文件已经打开,先关闭文件
	if (!m_OpenFileName.IsEmpty())
	{
		//如果保存,交给用户控制,让用户自己存,如果自己SAVE,会出现莫名的等待  
		if (ifSave)
		{

		}
		else
		{
			m_WorkBook.Close(COleVariant(short(FALSE)), COleVariant(m_OpenFileName), covOptional);
			m_Books.Close();
		}
		//清空打开文件名称
		m_OpenFileName.Empty();
	}

	m_Sheets.ReleaseDispatch();
	m_WorkSheet.ReleaseDispatch();
	m_CurRange.ReleaseDispatch();
	m_WorkBook.ReleaseDispatch();
	m_Books.ReleaseDispatch();
	//m_App.Quit();
	return;
}

3、再次打开表格对其操作

SYSTEMTIME sys;
	GetLocalTime(&sys);
	CString strFileName;


	strTmp.Format("%04d%02d%02d", sys.wYear, sys.wMonth, sys.wDay + 100);
	strFileName.Format("%s\\%s.xlsx", sPath, strTmp);  


	CApplication app;
	CWorkbooks books;
	CWorkbook book;
	CWorksheets sheets;
	CWorksheet sheet;
	CRange range;

	LPDISPATCH lpDisp = NULL;
	COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
	if (!app.CreateDispatch(_T("Excel.Application")))
	{
		MessageBox(_T("Error!Creat Excel Application Sever Fail!"));
		exit(1);
	}

	books.AttachDispatch(app.get_Workbooks());
	//获得所有工作表
	books.AttachDispatch(app.get_Workbooks());

	try
	{
		lpDisp = books.Open(strFileName, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional);
	}
	catch (CException* e)
	{
		// r如果该路径没有表格则生成一个表格
		CreatNewExcel(strFileName);
		// 再次打开
		lpDisp = books.Open(strFileName, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional);
		m_IsNewCreat = TRUE;
	}

	book.AttachDispatch(lpDisp);//得到Workbook  
	sheets.AttachDispatch(book.get_Worksheets());//得到Worksheets  

	lpDisp = book.get_ActiveSheet();//得到当前活跃sheet,如果有单元格正处于编辑状态中,此操作不能返回,会一直等待  
	sheet.AttachDispatch(lpDisp);

4、对表格数据进行填充 

        CString strTemp, strTemp1;
		CString str[] = { _T("时间(时分秒)") ,_T("结果"),"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20" };
		vector HeadString(str, str + 22);

		for (int i = 0; i < HeadString.size(); ++i)
		{

			range = sheet.get_Range(COleVariant(_T("A1")), COleVariant(_T("A1")));
			range.put_ColumnWidth(_variant_t((long)20)); // 指定区域 设置列宽

			COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);

	        range.AttachDispatch(sheet.get_Cells());
	        range.AttachDispatch(range.get_Item(COleVariant((long)nRow),       COleVariant((long)nCol)).pdispVal);

	        //  给单元格写入值
	        range.put_Value(covOptional, _variant_t(strValue));
             
            // 给单元格设置字体格式
            CFont0 ft;
		    ft.AttachDispatch(range.get_Font());
		    ft.put_Name(_variant_t(_T("宋体")));
		    ft.put_Size(_variant_t(8));
		    ft.put_Color(_variant_t(RGB(255, 0, 0)));
            
            // 给单元格设置底色
            interior.AttachDispatch(range.get_Interior());
	    	//将底色改为红色 44-对应浅黄色 具体数值对应颜色看这个链接             https://msdn.microsoft.com/en-us/library/cc296089.aspx
		    interior.put_ColorIndex(_variant_t((long)44));

		}

5、获取对应单元格的值,转为字符串输出

	int rows,cols; // 整数型行列,以获取指定单元格
    rows = 1;
    cols = 1;
    range.AttachDispatch(range.get_Item(COleVariant((long)rows), COleVariant((long)cols)).pdispVal);
    COleVariant vResult;
	vResult = range.get_Value2();
	CString data;
	if (vResult.vt == VT_BSTR) //字符串  
	{
		data = vResult.bstrVal;
	}
	else if (vResult.vt == VT_R8) //8字节的数字  
	{
		data.Format("%.0f", vResult.dblVal);
	}
	else if(vResult.vt==VT_EMPTY) //单元格空的
	{
		data = "";
	}

6、获取用户区域,对该区域的数值设置对齐方式。

CRange UseRange1;
	UseRange1.AttachDispatch(sheet.get_UsedRange(), true);
	range.AttachDispatch(UseRange1.get_Rows(), true);
	//设置合并单元格的文字的对齐方式【水平垂直居中、竖直垂直居中】   
	//水平对齐:默认=1,居中=-4108,左=-4131,右=-4152   
	//垂直对齐:默认=2,居中=-4108,左=-4160,右=-4107   
	UseRange1.put_HorizontalAlignment(_variant_t((long)-4108));
	UseRange1.put_VerticalAlignment(_variant_t((long)-4108));
	UseRange1.ReleaseDispatch();

7、结束别忘了保存数据然后关闭。不然再进程里会一直占用。

book.Save();

	books.Close();
	range.ReleaseDispatch();
	sheet.ReleaseDispatch();
	sheets.ReleaseDispatch();
	book.ReleaseDispatch();
	books.ReleaseDispatch();
	app.ReleaseDispatch();
	app.Quit();

至此就结束了excel的基本操作,其他的基本都是先找到单元格的位置,然后调用各自的接口进行想要的操作。接口不清楚只能去网上或者微软官网去查了。
Workbook 对象 (Excel) | Microsoft Docs

源码传送门:

你可能感兴趣的:(学习记录,MFC,c++)