欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

一步一步地教你实现OLE读取EXCEL(一)

程序员文章站 2024-03-24 13:46:58
...

OLE实现EXCEL读取的动态链接库的具体步骤

1.环境搭建:

我们需要什么环境背景呢?我用的是VS2015 + Microsoft Excel 2015,这里强调一下OLE不能在WPS上进行,因为OLE需要调用微软的基础类库(MFC),所以我们需要用到Excel软件,如果您用的是WPS,请出门右转!一步一步地教你实现OLE读取EXCEL(一)

2.具体步骤:

2.1创建工程:

我们要实现一个可以实现excel读取的动态链接库,当需要读取EXCEL时,直接加载dll即可实现excel读取,看图!一步一步地教你实现OLE读取EXCEL(一)
一步一步地教你实现OLE读取EXCEL(一)
选择MFC DLL,取名ExcelRead,点击确定。这样我们就在G盘生成了一个动态链接库的工程。
一步一步地教你实现OLE读取EXCEL(一)
一路下一步,记得在自动化的前面打上勾,点击完成。
一步一步地教你实现OLE读取EXCEL(一)
默认工程是debug和x86格式的,因为excel是64位的,所以我们将工程调整为x64,如果工程按照x86编译,会出现10处报错,例如:LPWSTR不能转换为char *类型,1.exe已退出等等,主要原因在于32位指令与64位指令的字符集是不一样的,32位指令用的是ASCII码指令字,64位指令的字符集是宽字符集,具体原因请百度一步一步地教你实现OLE读取EXCEL(一)
一步一步地教你实现OLE读取EXCEL(一)
在项目名处右键,点击添加->类。
一步一步地教你实现OLE读取EXCEL(一)
点击添加MFC中的typelib类中的MFC类,点击添加。
一步一步地教你实现OLE读取EXCEL(一)
在可用的类型库下拉框选择Microsoft Excel 16.0 Object Library,之后将图上6个类添加进去,点击完成!
一步一步地教你实现OLE读取EXCEL(一)
红色的框框里面是新生成的头文件,有6个头文件,分别定义了六个OLE的类。之后我们将绿色框里面的代码注释掉,红框里面的6个头文件都有这句代码,统统注释掉,否则,,,,呵呵,120个编译错误会等着你。。。一步一步地教你实现OLE读取EXCEL(一)
一步一步地教你实现OLE读取EXCEL(一)
在stdafx.h里面添加绿色框框里面的代码。之后你会看见下图。
一步一步地教你实现OLE读取EXCEL(一)
以CApplication.h为例,红色波浪线消失了有木有一步一步地教你实现OLE读取EXCEL(一),把#import "C:\\Program Files (x86)\\Microsoft Office\\Root\\Office16\\EXCEL.EXE" no_namespace那句注释掉之后界面如上图所示!
之后我们创建一个头文件以实现对OLE读取EXCEL类的定义。创建一个CExcelFileRead.h,代码如下:
#pragma once
// 用于OLE方式读取Excel文件
class CReadExcelFile				//对一个excel文件的读取操作
{
private:
	static CApplication excel_application;	//EXCEL进程实例,只有一个
	CWorkbooks excel_books;					// workbook集合(多个文件时)
	CWorkbook excel_work_book;				// 当时使用的workbook
	CWorksheets excel_sheets;				// worksheet集合
	CWorksheet excel_work_sheet;			// 当前使用的worksheet
	CRange excel_current_range;				// 当前操作的区域
	CString open_excel_file;				// 打开的Excel文件名称

	BOOL OpenFileFlag;						// 打开Excel文件是否失败

protected:
	// 使用某个sheet
	BOOL LoadSheet(long iSheet);
	BOOL LoadSheet(const char* sheet_name);

public:
	// 构造函数:打开Excel文件
	CReadExcelFile(const char* file_name);
	// 析构函数:关闭Excel文件
	~CReadExcelFile();
	// 判断是否打开成功
	BOOL IsOpenSuccess();
	// 初始化Excel OLE
	static BOOL InitExcel();
	// 释放Excel OLE
	static void ReleaseExcel();
	// 取得打开的文件名称
	CString GetCurrentFileName();
	// 得到Sheet的总数
	int GetSheetCount();
	// 取得某个Sheet的名称
	CString GetSheetName(long iSheet);
	// 取得行的总数
	int GetRowCount(long iSheet);
	// 取得列的总数
	int GetColCount(long iSheet);
	// 根据Sheet名称获得Sheet标号
	int GetSheetIndex(const char * sheet_name);
	// 得到一个Cell的String
	CString GetCellString(long iSheet, long iRow, long iCol);
	// 得到一个Cell的Int
	int GetCellInt(long iSheet, long iRow, long iCol);
	// 得到一个Cell的double
	double GetCellDouble(long iSheet, long iRow, long iCol);
	// 检查一个Cell是否空
	BOOL IsCellEmpty(long iSheet, long iRow, long iCol);
	// 检查一个Cell是否是字符串
	BOOL IsCellString(long iSheet, long iRow, long iCol);
	// 检查一个Cell是否是数值
	BOOL IsCellInt(long iSheet, long iRow, long iCol);
	// 取得列的名称(如第27列为AA)
	static CString GetColName(long iCol);
};
创建头文件的实现文件CExcelFileRead.cpp中定义以下代码。
#include "stdafx.h"
#include "CExcelFileRead.h"

COleVariant covTrue((short)TRUE), covFalse((short)FALSE), covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
// Excel App初始化
CApplication CReadExcelFile::excel_application;
// 初始化Excel OLE
BOOL CReadExcelFile::InitExcel()
{
	// 初始化COM库
	CoInitialize(NULL);
	// 初始化Excel
	if (!excel_application.CreateDispatch("Excel.Application", NULL))return FALSE;
	excel_application.put_DisplayAlerts(FALSE);		// 屏蔽警告
	return TRUE;
}
// 释放Excel OLE
void CReadExcelFile::ReleaseExcel()
{
	excel_application.ReleaseDispatch();
	excel_application.Quit();
	excel_application = NULL;
}
// 构造函数
CReadExcelFile::CReadExcelFile(const char * file_name)
{
	// 连接excel app
	excel_books.AttachDispatch(excel_application.get_Workbooks());
	// 打开文件并初始化excel_work_book
	LPDISPATCH lpDisp = NULL;
	TRY
	{
		lpDisp = excel_books.Open(file_name, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional);
	}
		CATCH(COleDispatchException, e)
	{
		AfxMessageBox(e->m_strDescription);
		OpenFileFlag = FALSE;
		return;
	}
	END_CATCH
		OpenFileFlag = TRUE;
	excel_work_book.AttachDispatch(lpDisp);
	// 得到所有的sheets并初始化excel_sheets
	excel_sheets.AttachDispatch(excel_work_book.get_Worksheets());
	// 得到活动的工作表并初始化excel_work_sheet
	excel_work_sheet.AttachDispatch(excel_work_book.get_ActiveSheet());
	// 初始化当前的操作区域excel_current_range
	excel_current_range.AttachDispatch(excel_work_sheet.get_Cells());
	// 设置当前的文件名
	open_excel_file = file_name;
}
// 析构函数:关闭文件
CReadExcelFile::~CReadExcelFile()
{
	excel_books.Close();
}
// 判断是否打开成功
BOOL CReadExcelFile::IsOpenSuccess() { return OpenFileFlag; }
// 返回打开的Excel文件名称
CString CReadExcelFile::GetCurrentFileName()
{
	return open_excel_file;
}
// 加载某个Sheet,通过index
BOOL CReadExcelFile::LoadSheet(long iSheet)
{
	if (iSheet > excel_sheets.get_Count())return FALSE;
	// 如果iSheet当前已经加载
	if (iSheet == excel_work_sheet.get_Index())return TRUE;
	// 释放先前的
	excel_current_range.ReleaseDispatch();
	excel_work_sheet.ReleaseDispatch();
	// 加载iSheet
	LPDISPATCH lpDisp = excel_sheets.get_Item(COleVariant((long)iSheet));
	if (!lpDisp)return FALSE;
	excel_work_sheet.AttachDispatch(lpDisp);
	excel_current_range.AttachDispatch(excel_work_sheet.get_Cells());
	return TRUE;
}
// 加载某个Sheet,通过名称
BOOL CReadExcelFile::LoadSheet(const char * sheet_name)
{
	// 如果iSheet当前已经加载
	if (excel_work_sheet.get_Name() == sheet_name)return TRUE;
	// 释放先前的
	excel_current_range.ReleaseDispatch();
	excel_work_sheet.ReleaseDispatch();
	// 加载iSheet
	LPDISPATCH lpDisp = excel_sheets.get_Item(COleVariant(sheet_name));
	if (!lpDisp)return FALSE;
	excel_work_sheet.AttachDispatch(lpDisp);
	excel_current_range.AttachDispatch(excel_work_sheet.get_Cells());
	return TRUE;
}
// 获得sheet数目
int CReadExcelFile::GetSheetCount()
{
	return excel_sheets.get_Count();
}
// 获得某个Sheet的名称
CString CReadExcelFile::GetSheetName(long iSheet)
{
	// 加载iSheet
	if (!LoadSheet(iSheet))return CString();
	return excel_work_sheet.get_Name();
}
// 获得某个Sheet的row数目
int CReadExcelFile::GetRowCount(long iSheet)
{
	// 加载iSheet
	if (!LoadSheet(iSheet))return 0;
	// 获取使用范围usedRange,获取行range
	CRange usedRange; usedRange.AttachDispatch(excel_work_sheet.get_UsedRange());
	CRange range;     range.AttachDispatch(usedRange.get_Rows());
	// 获得数目
	int count = range.get_Count();
	// 释放
	usedRange.ReleaseDispatch();
	range.ReleaseDispatch();
	// 返回
	return count;
}
// 获得某个Sheet的column数目
int CReadExcelFile::GetColCount(long iSheet)
{
	// 加载iSheet
	if (!LoadSheet(iSheet))return 0;
	// 获取使用范围usedRange,获取行range
	CRange usedRange; usedRange.AttachDispatch(excel_work_sheet.get_UsedRange());
	CRange range;     range.AttachDispatch(usedRange.get_Columns());
	// 获得数目
	int count = range.get_Count();
	// 释放
	usedRange.ReleaseDispatch();
	range.ReleaseDispatch();
	// 返回
	return count;
}
// 根据Sheet的名称获得Sheet的index
int CReadExcelFile::GetSheetIndex(const char * sheet_name)
{
	if (!LoadSheet(sheet_name))return -1;
	return excel_work_sheet.get_Index();
}
// 获得某个Sheet的字符串Cell
CString CReadExcelFile::GetCellString(long iSheet, long iRow, long iCol)
{
	// 加载iSheet
	if (!LoadSheet(iSheet))return CString();
	// 读取
	CRange range;	range.AttachDispatch(excel_current_range.get_Item(COleVariant((long)iRow), COleVariant((long)iCol)).pdispVal);
	COleVariant vResult = range.get_Value2();
	range.ReleaseDispatch();
	// 分析vResult
	CString str;
	if (vResult.vt == VT_BSTR)str = vResult.bstrVal;					// 字符串 
	else if (vResult.vt == VT_INT)str.Format(_T("%d"), vResult.pintVal);	// 整数
	else if (vResult.vt == VT_R8)str.Format(_T("%0.0f"), vResult.dblVal);	// 8字节的整数
	else if (vResult.vt == VT_DATE)										// 时间格式
	{
		SYSTEMTIME st; VariantTimeToSystemTime(vResult.date, &st);
		CTime tm(st);	str = tm.Format("%Y-%m-%d");
	}
	else if (vResult.vt == VT_EMPTY)str = "";							// 空的单元格
	else str = "";
	return str;
}
// 获得某个Sheet的整数Cell
int CReadExcelFile::GetCellInt(long iSheet, long iRow, long iCol)
{
	// 加载iSheet
	if (!LoadSheet(iSheet))return 0;
	// 读取
	CRange range;	range.AttachDispatch(excel_current_range.get_Item(COleVariant((long)iRow), COleVariant((long)iCol)).pdispVal);
	COleVariant vResult = range.get_Value2();
	range.ReleaseDispatch();
	// 分析vResult
	int num = static_cast<int>(vResult.dblVal);
	return num;
}
// 获得某个Sheet的浮点数Cell
double CReadExcelFile::GetCellDouble(long iSheet, long iRow, long iCol)
{
	// 加载iSheet
	if (!LoadSheet(iSheet))return 0.0;
	// 读取
	CRange range;	range.AttachDispatch(excel_current_range.get_Item(COleVariant((long)iRow), COleVariant((long)iCol)).pdispVal);
	COleVariant vResult = range.get_Value2();
	range.ReleaseDispatch();
	// 分析vResult
	double rtn_value = 0.0;
	if (vResult.vt == VT_R8)rtn_value = vResult.dblVal;
	return rtn_value;
}
// 检查Cell是否空
BOOL CReadExcelFile::IsCellEmpty(long iSheet, long iRow, long iCol)
{
	// 加载iSheet
	if (!LoadSheet(iSheet))return TRUE;
	// 读取
	CRange range;	range.AttachDispatch(excel_current_range.get_Item(COleVariant((long)iRow), COleVariant((long)iCol)).pdispVal);
	COleVariant vResult = range.get_Value2();
	range.ReleaseDispatch();
	// 分析vResult
	if (vResult.vt == VT_EMPTY)return TRUE;
	else return FALSE;
}
// 检查Cell是否是字符串
BOOL CReadExcelFile::IsCellString(long iSheet, long iRow, long iCol)
{
	// 加载iSheet
	if (!LoadSheet(iSheet))return FALSE;
	// 读取
	CRange range;	range.AttachDispatch(excel_current_range.get_Item(COleVariant((long)iRow), COleVariant((long)iCol)).pdispVal);
	COleVariant vResult = range.get_Value2();
	//VT_BSTR标示字符串  
	if (vResult.vt == VT_BSTR)return TRUE;
	return FALSE;
}
// 检查Cell是否是int
BOOL CReadExcelFile::IsCellInt(long iSheet, long iRow, long iCol)
{
	// 加载iSheet
	if (!LoadSheet(iSheet))return FALSE;
	// 读取
	CRange range;	range.AttachDispatch(excel_current_range.get_Item(COleVariant((long)iRow), COleVariant((long)iCol)).pdispVal);
	COleVariant vResult = range.get_Value2();
	// 检查
	if (vResult.vt == VT_INT || vResult.vt == VT_R8)return TRUE;
	return FALSE;
}
// 取得列的名称(如第27列为AA)
CString CReadExcelFile::GetColName(long iCol)
{
	// 初始化column_name
	char column_name[64];
	// 分析iCol
	size_t str_len = 0; while (iCol > 0)
	{
		int num_data = iCol % 26;
		iCol /= 26;
		if (num_data == 0)
		{
			num_data = 26;
			iCol--;
		}
		column_name[str_len] = (char)((num_data - 1) + 'A');
		str_len++;
	}
	column_name[str_len] = '\0';
	// 反转
	_strrev(column_name);
	// 返回
	return CString(column_name);
}
创建一个对外接口头文件DLL_API.h文件,代码如下:
#pragma once
//--------------------------------------------------------------------//
// DLL对外接口函数:
//     1.完成Excel OLE的初始化
//     2.给出要读取的文件名、Sheet标号、列数、行数等相关信息进行读取;
//     3.完成Excel OLE的释放
//--------------------------------------------------------------------//
// 维护函数:
//     维护函数实现从读取函数到CReadExcel类对象的过程实现和维护。在得到
// 用户调用的读取函数之后,维护函数判断该文件是否已经打开:
//     1.如果已经打开,那么到OpenFileList中找到对应的CReadExcelFile类的
// 指针,并进行后续的操作;
//     2.如果没有打开,那么申请一个新的CReadExcelFile类并将其存入打开文
// 件列表OpenFileList,之后进行后续操作;
//--------------------------------------------------------------------//
#pragma once
#include "CExcelFileRead.h"
#include<vector>
#define DLL_API extern "C" __declspec(dllexport)

using namespace std;

//----DLL全局变量:读取文件记录---------------------------------------//
vector<CReadExcelFile*> OpenFileList;

//----DLL对外接口函数-------------------------------------------------//
// 完成Excel OLE的初始化
DLL_API bool Excel_Init();
// 完成Excel OLE的释放
DLL_API void Excel_Release();
// 得到某文件Sheet的总数
DLL_API int get_sheets_count(string &file_name);
// 得到某文件某个Sheet的名称
DLL_API string get_sheet_name(string &file_name, long iSheet);
// 得到某个文件某个Sheet的行数
DLL_API int get_rows_count(string &file_name, long iSheet);
// 得到某个文件某个Sheet的列数
DLL_API int get_cols_count(string &file_name, long iSheet);
// 根据Sheet名称获得Sheet标号
DLL_API int get_sheet_index(string &file_name, string &sheet_name);
// 得到某个文件某个Sheet某个Cell(字符串)
DLL_API string get_cell_string(string &file_name, long iSheet, long iRows, long iCols);
// 得到某个文件某个Sheet某个Cell(整数)
DLL_API int get_cell_int(string &file_name, long iSheet, long iRows, long iCols);
// 得到某个文件某个Sheet某个Cell(浮点数)
DLL_API double get_cell_double(string &file_name, long iSheet, long iRows, long iCols);
// 判断Cell是否空
DLL_API bool IsCellEmpty(string &file_name, long iSheet, long iRows, long iCols);


//----维护函数,对外不可见---------------------------------------------//
// 在OpenFileList中寻找某文件的index,不存在返回-1
int FindFileIndexInList(string &file_name);
// 总维护过程
CReadExcelFile *Maintain(string &file_name);
// 释放Excel OLE时要清空列表,析构其中所有CReadExcelFile类
void CloseAllFile();


创建一个实现文件DLL_API.cpp,代码如下:
#include "stdafx.h"
#include "DLL_API.h"

//--维护函数的实现----------------------------------------------------//
// 在OpenFileList中寻找某文件的index,不存在返回-1
int FindFileIndexInList(string &file_name)
{
	for (int index = 0; index < OpenFileList.size(); index++)
		if (OpenFileList.at(index)->GetCurrentFileName() == file_name.c_str())
			return index;
	return -1;
}
// 总维护过程
CReadExcelFile *Maintain(string &file_name)
{
	// 在OpenFileList中寻找某文件
	int index = FindFileIndexInList(file_name);
	// 如果找到,返回指针
	if (index != (-1))return OpenFileList.at(index);
	// 如果未找到,新打开一个文件
	CReadExcelFile *new_file = new CReadExcelFile(file_name.c_str());
	// 若打开文件失败,关闭所有文件,释放Excel OLE并退出
	if (!(new_file->IsOpenSuccess()))
	{
		delete new_file;
		CloseAllFile();
		Excel_Release();
		exit(1);
	}
	// 否则,将新文件存入打开文件列表
	OpenFileList.push_back(new_file);
	return new_file;
}
// 释放Excel OLE时要清空列表,析构其中所有CReadExcelFile类
void CloseAllFile()
{
	for (int index = 0; index < OpenFileList.size(); index++)
		delete OpenFileList.at(index);
	OpenFileList.clear();
}


//--DLL对外接口函数的实现---------------------------------------------//
// 完成Excel OLE的初始化
bool Excel_Init()
{
	if (CReadExcelFile::InitExcel())return true;
	else return false;
}
// 完成Excel OLE的释放
void Excel_Release()
{
	CloseAllFile();
	CReadExcelFile::ReleaseExcel();
}
// 得到某文件Sheet的总数
int get_sheets_count(string &file_name)
{
	CReadExcelFile *file = Maintain(file_name);
	return file->GetSheetCount();
}
// 得到某文件某个Sheet的名称
string get_sheet_name(string &file_name, long iSheet)
{
	CReadExcelFile *file = Maintain(file_name);
	return file->GetSheetName(iSheet);
}
// 得到某个文件某个Sheet的行数
int get_rows_count(string &file_name, long iSheet)
{
	CReadExcelFile *file = Maintain(file_name);
	return file->GetRowCount(iSheet);
}
// 得到某个文件某个Sheet的列数
int get_cols_count(string &file_name, long iSheet)
{
	CReadExcelFile *file = Maintain(file_name);
	return file->GetColCount(iSheet);
}
// 根据Sheet名称获得Sheet标号
int get_sheet_index(string &file_name, string &sheet_name)
{
	CReadExcelFile *file = Maintain(file_name);
	return file->GetSheetIndex(sheet_name.c_str());
}
// 得到某个文件某个Sheet某个Cell(字符串)
string get_cell_string(string &file_name, long iSheet, long iRows, long iCols)
{
	CReadExcelFile *file = Maintain(file_name);
	return file->GetCellString(iSheet, iRows, iCols);
}
// 得到某个文件某个Sheet某个Cell(整数)
int get_cell_int(string &file_name, long iSheet, long iRows, long iCols)
{
	CReadExcelFile *file = Maintain(file_name);
	return file->GetCellInt(iSheet, iRows, iCols);
}
// 得到某个文件某个Sheet某个Cell(浮点数)
double get_cell_double(string &file_name, long iSheet, long iRows, long iCols)
{
	CReadExcelFile *file = Maintain(file_name);
	return file->GetCellDouble(iSheet, iRows, iCols);
}
// 判断Cell是否空
bool IsCellEmpty(string &file_name, long iSheet, long iRows, long iCols)
{
	CReadExcelFile *file = Maintain(file_name);
	return file->IsCellEmpty(iSheet, iRows, iCols);
}
下图为本动态链接库工程的文件结构:
一步一步地教你实现OLE读取EXCEL(一)
OK,我们的动态链接库完成,点击运行,会在工程文件夹下面的x64/debug文件夹里面生成一个dll文件,在下面的章节中我会为大家介绍这个dll怎么使用。本工程代码在第二节里面有连接。
下一章节附有代码连接,连接如下:http://download.csdn.net/download/qq_35747066/10205399
本文原创,如果您按照本人的教程一步一步地实现发生了错误,生成不了dll,请立即联系我,本人的QQ号:1012638836.本人会及其所能的帮助你。一步一步地教你实现OLE读取EXCEL(一)