1. 程式人生 > >一步一步地教你實現OLE讀取EXCEL(一)

一步一步地教你實現OLE讀取EXCEL(一)

#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,程式碼如下:

相關推薦

實現OLE讀取EXCEL

#include "stdafx.h" #include "CExcelFileRead.h" COleVariant covTrue((short)TRUE), covFalse((short)FALSE), covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERRO

實現OLE讀取EXCEL

在上一篇中本人向大家介紹了OLE讀取EXCEL檔案所用到的動態連結庫的方法!下面這一章節為大家介紹簡單的UI介面以及使用DLL的方法! (一)介面 介面很垃圾,內容很樸實。在lineedit中輸入學生姓名後點擊“開始搜尋”,之後在textedit顯示該學生參加的社會實踐

前端學UI——人物處理

適應 logs 減少 方法 情況 總結 -a 但是 影響 一、序言 本文作為本系列的第一篇寫UI的文章,開頭還是有必要申明一些東西的,本系列主要是為了作為博主在前端工作之余學習UI的一個記錄,同時為了讓更多的同行學習到一些編程之外的其他東西。所以本文會盡可能詳細的介紹如何

手把手開發jquery插件

PE ora ID outside sep write -c visio .sh Just as the auther of jQuery Tools said: 上海代孕 http://www.xyrjkf.cn/ jQuery UI has a so-called

手把手移植linux核心---------OK6410

配置資訊: 移植核心:linux-3.3.5       可以從  http://www.kernel.org/     下載純正的版本    編譯環境:vmware下ubuntu11.04 交叉編譯版本:4.3.2 準備工作: 一塊OK6410開發板,交叉網線,串列埠線

寫響應式框架

在真正開始編寫自己的響應式框架之前,我們先來從觀察者模式說起。已經對觀察者模式很熟悉的可以直接掠過。 基本概念 觀察者模式屬於物件行為模式之一,也可叫做釋出——訂閱模式。它定義了一種以對多的依賴關係,讓多個觀察者(訂閱者)同時觀察(監聽)一個被觀察者(主

手把手做智慧LED燈 功能規劃與設計方案

前言 智慧硬體有意思,現在市場上有很多針對普通消費者的智慧硬體。例如,智慧燈泡、智慧插座、智慧電子秤,甚至無人飛行器。拋開這些智慧裝置實現的功能不談,它們的實現原理都是大同小異:通過手機的藍芽(或者wifi網路),連線智慧硬體上的藍芽模組,向藍芽模組傳送各種控

【教程】步步使用以太坊ETH錢包

很多小夥伴不知道選擇怎樣的以太坊錢包,下載以太坊PC端錢包更新太慢而且交易不方便,那麼我推薦大家使用GTETH以太坊錢包,操作方便非常安全的以太坊錢包 詳細介紹GTETH以太坊錢包教程 建立錢包(網頁版/桌面軟體/手機軟體),備份錢包(一定要拿到私鑰,不見私鑰千萬不要

玩App怎麼賺錢

       在看這篇文章之前,你一定要接受一下謀哥的觀點:金錢就是價值流通的手段,不要高看了錢。   玩App怎麼賺錢?貌似謀哥寫的文章超級多,把這個最重要的忘記了。說實在的,我為啥要寫“玩App"呢?其實就是一種比較輕鬆的心態。就好像現在我寫文章,簡直就是神速,那思路就

手把手寫fio 插件

type 添加 libaio sample rev any ins The direct FIO是一款方便IO性能測試的工具,以統計全面、模式靈活深得用戶歡心。當前支持libaio、sync等IO引擎。在存儲系統開發中,如何快速快速全面評測系統IO性能?給FIO添加調用存儲

分分鐘學會 ToolBar 的使用

window map pri end case instance em1 oom title 轉自:http://blog.csdn.net/itguangit/article/details/52042203 1.和平常一樣,新建一個Moudle 在xml布局文件中使用

建立Oracle複合索引

什麼是複合索引? 複合索引顧名思義,區別於單列索引,是由兩個或多個列一起構成的索引。其在B樹上的資料結構是什麼樣?如下圖,是一個包含兩列的複合索引。 如果你觀察仔細,還會發現它的葉子節點是ASC遞增排序的。現根據第一個值排序,然後根據第二個值排序。查的時候也一樣,先查第一個值,在查

手把手構建 C 語言編譯器6

由於語法分析本身比較複雜,所以我們將它拆分成 3 個部分進行講解,分別是:變數定義、函式定義、表示式。本章講解函式定義相關的內容。 手把手教你構建 C 語言編譯器系列共有10個部分: EBNF 表示 這是上一章的 EBNF 方法中與函式定義相關的內容。 variable_decl ::= type {'*

手把手構建 C 語言編譯器4

本章我們將講解遞迴下降的方法,並用它完成一個基本的四則運算的語法分析器。 手把手教你構建 C 語言編譯器系列共有10個部分: 什麼是遞迴下降 傳統上,編寫語法分析器有兩種方法,一種是自頂向下,一種是自底向上。自頂向下是從起始非終結符開始,不斷地對非終結符進行分解,直到匹配輸入的終結符;自底向上是不斷地將終

手把手構建 C 語言編譯器8

這是整個編譯器的最後一部分,解析表示式。什麼是表示式?表示式是將各種語言要素的一個組合,用來求值。例如:函式呼叫、變數賦值、運算子運算等等。 表示式的解析難點有二:一是運算子的優先順序問題,二是如何將表示式編譯成目的碼。我們就來逐一說明。 手把手教你構建 C 語言編譯器系列共有10個部分: 運算子的優先順

手把手構建 C 語言編譯器2

本章是“手把手教你構建 C 語言編譯器”系列的第三篇,本章我們要構建一臺虛擬的電腦,設計我們自己的指令集,執行我們的指令集,說得通俗一點就是自己實現一套匯編語言。它們將作為我們的編譯器最終輸出的目的碼。 手把手教你構建 C 語言編譯器系列共有10個部分: #計算機的內部工作原理 計算機中有三個基本部件需要

手把手構建 C 語言編譯器5

本章中我們用 EBNF 來大致描述我們實現的 C 語言的文法,並實現其中解析變數定義部分。 由於語法分析本身比較複雜,所以我們將它拆分成 3 個部分進行講解,分別是:變數定義、函式定義、表示式。 手把手教你構建 C 語言編譯器系列共有10個部分: EBNF 表示 EBNF 是對前一章提到的 BNF 的擴充

手把手構建 C 語言編譯器9

恭喜你完成了自己的 C 語言編譯器,本章中我們發一發牢騷,說一說編寫編譯器值得注意的一些問題;編寫編譯器時遇到的一些難題。 手把手教你構建 C 語言編譯器系列共有10個部分: 虛擬機器與目的碼 整個系列的一開始,我們就著手虛擬機器的實現。不知道你是否有同感,這部分對於整個編譯器的編寫其實是十分重要的。我認

手把手構建 C 語言編譯器1

本章是“手把手教你構建 C 語言編譯器”系列的第二篇,我們要從整體上講解如何設計我們的 C 語言編譯器。 手把手教你構建 C 語言編譯器系列共有10個部分: 首先要說明的是,雖然標題是編譯器,但實際上我們構建的是 C 語言的直譯器,這意味著我們可以像執行指令碼一樣去執行 C 語言的原始碼檔案。這麼做的理由

手把手構建 C 語言編譯器0

“手把手教你構建 C 語言編譯器” 這一系列教程將帶你從頭編寫一個 C 語言的編譯器。希望通過這個系列,我們能對編譯器的構建有一定的瞭解,同時,我們也將構建出一個能用的 C 語言編譯器,儘管有許多語法並不支援。 手把手教你構建 C 語言編譯器系列共有10個部分: 在開始進入正題之前,本篇是一些閒聊,談談這