在工控領(lǐng)域,上位機(jī)經(jīng)常需要操作excel,用于保存測(cè)試的數(shù)據(jù)及測(cè)試結(jié)果。LabwindowsCVI提供了專(zhuān)門(mén)工具庫(kù)ExcelReport實(shí)現(xiàn)對(duì)Excel操作。ExcelReport庫(kù)就是對(duì)windows的excel庫(kù)進(jìn)行了一層封裝,這樣我們就能更好的操作excel了,同時(shí)也要求計(jì)算機(jī)上要安裝Excel軟件。Excelreport.fp的主要函數(shù)如下圖。

下面將介紹操作Excel的常用API:
1、ExcelRpt_ApplicationNew
ExcelRpt_ApplicationNew用于啟動(dòng)excel程序,其函數(shù)原型如下所示:
HRESULT CVIFUNC ExcelRpt_ApplicationNew (int makeVisible, CAObjHandle *applicationHandle);
其中makeVisible為加載的excel程序是否顯示的標(biāo)志,當(dāng)其值為1時(shí),顯示excel程序界面,如下圖所示,applicationHandle為獲取的excel程序句柄。
2、ExcelRpt_WorkbookOpen
ExcelRpt_WorkbookOpen用于打開(kāi)excel的文件,其函數(shù)原型如下所示:
HRESULT CVIFUNC ExcelRpt_WorkbookOpen (CAObjHandle applicationHandle, const char *fileName,CAObjHandle *workbookHandle);
其中applicationHandle為excel程序的句柄,fileName為要打開(kāi)的excel文件路徑,workbookHandle為獲取的excel文件句柄。
3、ExcelRpt_GetWorksheetFromIndex
ExcelRpt_GetWorksheetFromIndex為獲取excel文件中某個(gè)sheet句柄,其函數(shù)原型如下所示:
HRESULT CVIFUNC ExcelRpt_GetWorksheetFromIndex (CAObjHandle workbookHandle, int Index,CAObjHandle *worksheetHandle);
其中workbookHandle為excel文件的句柄,Index為excel文件中sheet的索引,其索引值從1開(kāi)始,worksheetHandle為獲得的sheet句柄。
4、ExcelRpt_GetCellValue
ExcelRpt_GetCellValue為獲取sheet中某cell的內(nèi)容,其函數(shù)原型如下所示:
HRESULT CVIFUNC ExcelRpt_GetCellValue (CAObjHandle worksheetHandle, const char *cellRange,enum ExREnum_ExDataType dataType, void *dataValue);
其中worksheetHandle為sheet句柄,cellRange為cell的索引,dataType為數(shù)據(jù)類(lèi)型,通常情況下,該值設(shè)置為CAVT_CSTRING,這樣我們可以讀取各種數(shù)據(jù),然后進(jìn)行轉(zhuǎn)換,dataValue為讀取的數(shù)據(jù)指針。
5、ExcelRpt_SetCellValue
ExcelRpt_SetCellValue用于設(shè)置sheet中某cell內(nèi)容,其函數(shù)原型如下所示:
HRESULT ExcelRpt_SetCellValue (CAObjHandle worksheetHandle, char cellRange[], enum ExREnum_ExDataType dataType, ...);
其中worksheetHandle為sheet句柄,cellRange為cell的索引,dataType為數(shù)據(jù)類(lèi)型。
6、ExcelRpt_SetCellRangeAttribute
ExcelRpt_SetCellRangeAttribute為設(shè)置cell的屬性值,其函數(shù)原型如下所示:
HRESULT CVIFUNC_C ExcelRpt_SetCellRangeAttribute (CAObjHandle worksheetHandle, const char* cellRange,int attribute, ...);
其中worksheetHandle為sheet句柄,cellRange為cell的索引,attribute為屬性的名稱(chēng),…為屬性的值。在測(cè)試中,我們經(jīng)常使用該函數(shù)用于設(shè)置cell的背景顏色,用于直觀感受是否測(cè)試通過(guò)。
7、ExcelRpt_WorkbookClose
ExcelRpt_WorkbookClose用于關(guān)閉打開(kāi)的excel文件,其函數(shù)原型如下所示: HRESULT CVIFUNC ExcelRpt_WorkbookClose (CAObjHandle workbookHandle, int saveChanges);
其中workbookHandle為excel打開(kāi)文件的句柄,saveChanges為關(guān)閉時(shí),是否保存excel文件的標(biāo)志,通常我們?cè)O(shè)置該值為1,否則測(cè)試的數(shù)據(jù)將保存不了。
8、ExcelRpt_ApplicationQuit
ExcelRpt_ApplicationQuit用于關(guān)閉打開(kāi)的excel程序,其函數(shù)原型如下所示:
HRESULT CVIFUNC ExcelRpt_ApplicationQuit (CAObjHandle applicationHandle);
其中applicationHandle為打開(kāi)的excel程序?qū)嵗浔?/p>
9、ExcelRpt_GetErrorInfo
ExcelRpt_GetErrorInfo用于得到操作excel異常原因,其函數(shù)原型如下所示:
ERRORINFO * CVIFUNC ExcelRpt_GetErrorInfo(void);
該函數(shù)返回ERRORINFO的指針,我們可以觀察ERRORINFO-> description的異常描述。
10、CA_DiscardObjHandle
CA_DiscardObjHandle用于釋放objHandle對(duì)象,其函數(shù)原型如下所示:
HRESULT CVIFUNC CA_DiscardObjHandle(CAObjHandle objHandle);
項(xiàng)目實(shí)踐:
本項(xiàng)目模擬試驗(yàn)情況生成試驗(yàn)報(bào)告。
為了簡(jiǎn)化代碼,首先建一個(gè)試驗(yàn)報(bào)告模板。每次只需要向EXCEL里面添加對(duì)應(yīng)數(shù)據(jù)即可。
報(bào)告中的圖表是事先定義好的,只要數(shù)據(jù)填進(jìn)去自動(dòng)更新。實(shí)際上你也可以通過(guò)代碼插入chart圖表。

全部代碼如下:
#include "excelreport.h"
#include "time.h"
#include <ansi_c.h>
#include <utility.h>
#include <cvirte.h>
#include <userint.h>
#include "CviExcelRpt.h"
static int panelHandle;
//定義句柄變量
static CAObjHandle applicationHandle = 0;
static CAObjHandle workbookHandle = 0;
static CAObjHandle worksheetHandle = 0;
//定義含路徑的文件名變量
char ExcelFileName[MAX_PATHNAME_LEN]={0};
#define LAUNCHERR "\
An error occurred trying to launch Excel through its automation interface.\n\n\
Ensure that Excel is installed and that you can launch it manually."
//產(chǎn)品代號(hào)
static char ProductID[128]={0};
//試驗(yàn)單位
static char TestCompany[128]={0};
//操作員
static char Operator[128]={0};
//試驗(yàn)日期
static char TestDate[20]={0};
//試驗(yàn)時(shí)間
static char TestTime[20]={0};
//工作壓力
static double TestMPa=0.0;
//試驗(yàn)溫度
static double TestTemperature=10.0;
//試驗(yàn)時(shí)長(zhǎng)
static int TestDuration=10;
//試驗(yàn)項(xiàng)目1-4結(jié)果
static BOOL Test1Rst=FALSE;
static BOOL Test2Rst=FALSE;
static BOOL Test3Rst=FALSE;
static BOOL Test4Rst=FALSE;
//生產(chǎn)新報(bào)告的名字=report+年月日時(shí)分秒.xls
static char NewRptFileName[128]={0};
//獲取面板上設(shè)定的試驗(yàn)內(nèi)容
void GetTestResult()
{
GetCtrlVal(panelHandle,PANEL_PRODUCTID,ProductID);
GetCtrlVal(panelHandle,PANEL_TESTCOMPANY,TestCompany);
GetCtrlVal(panelHandle,PANEL_OPERATOR,Operator);
GetCtrlVal(panelHandle,PANEL_MPa,&TestMPa);
GetCtrlVal(panelHandle,PANEL_TEMPERATURE,&TestTemperature);
GetCtrlVal(panelHandle,PANEL_TESTTIME,&TestDuration);
GetCtrlVal(panelHandle,PANEL_TEST1,&Test1Rst);
GetCtrlVal(panelHandle,PANEL_TEST2,&Test2Rst);
GetCtrlVal(panelHandle,PANEL_TEST3,&Test3Rst);
GetCtrlVal(panelHandle,PANEL_TEST4,&Test4Rst);
time_t NowTime;
time(&NowTime);
struct tm *Now;
Now = localtime(&NowTime);
//生成試驗(yàn)日期
sprintf(TestDate,"%04d-%02d-%02d",Now->tm_year+1900,Now->tm_mon,Now->tm_mday);
//生成試驗(yàn)時(shí)間
sprintf(TestTime,"%02d:%02d:%02d",Now->tm_hour,Now->tm_min,Now->tm_sec);
//生成新試驗(yàn)報(bào)告名
sprintf(NewRptFileName,"\\report%04d%02d%02d%02d%02d%02d.xls",Now->tm_year+1900,Now->tm_mon,Now->tm_mday,Now->tm_hour,Now->tm_min,Now->tm_sec);
}
int main (int argc, char *argv[])
{
if (InitCVIRTE (0, argv, 0) == 0)
return -1; /* out of memory */
if ((panelHandle = LoadPanel (0, "CviExcelRpt.uir", PANEL)) < 0)
return -1;
DisplayPanel (panelHandle);
RunUserInterface ();
DiscardPanel (panelHandle);
return 0;
}
int CVICALLBACK panelCB (int panel, int event, void *callbackData,
int eventData1, int eventData2)
{
switch (event)
{
case EVENT_GOT_FOCUS:
break;
case EVENT_LOST_FOCUS:
break;
case EVENT_CLOSE:
break;
}
return 0;
}
int CVICALLBACK btnCreateRpt (int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
{
HRESULT error = 0;
switch (event)
{
//插入圖表的橫坐標(biāo)縱坐標(biāo)值cell號(hào)和值
char index[8]={0};
char data[8]={0};
int datavalue=0;
case EVENT_COMMIT:
error = ExcelRpt_ApplicationNew(1, &applicationHandle);
if (error<0)
{
MessagePopup ("Error: Microsoft Excel Automation", LAUNCHERR);
return 0;
}
GetProjectDir(ExcelFileName);
strcat(ExcelFileName,"\\report.xls");
//打開(kāi)報(bào)告模板文件
ExcelRpt_WorkbookOpen(applicationHandle,ExcelFileName,&workbookHandle);
//獲取想激活worksheet的句柄
ExcelRpt_GetWorksheetFromName(workbookHandle,"Sheet1",&worksheetHandle);
//激活指定sheet
ExcelRpt_ActivateWorksheet(worksheetHandle);
GetTestResult();
//向報(bào)告中插入試驗(yàn)數(shù)據(jù)
ExcelRpt_SetCellValue(worksheetHandle,"C3",ExRConst_dataString,ProductID);
ExcelRpt_SetCellValue(worksheetHandle,"C4",ExRConst_dataString,TestCompany);
ExcelRpt_SetCellValue(worksheetHandle,"C5",ExRConst_dataString,Operator);
ExcelRpt_SetCellValue(worksheetHandle,"F4",ExRConst_dataString,TestDate);
ExcelRpt_SetCellValue(worksheetHandle,"F5",ExRConst_dataString,TestTime);
ExcelRpt_SetCellValue(worksheetHandle,"C7",ExRConst_dataDouble,TestMPa);
ExcelRpt_SetCellValue(worksheetHandle,"C8",ExRConst_dataInt,TestDuration);
ExcelRpt_SetCellValue(worksheetHandle,"C9",ExRConst_dataDouble,TestTemperature);
if(Test1Rst)
ExcelRpt_SetCellValue(worksheetHandle,"F19",ExRConst_dataString,"合格");
else
ExcelRpt_SetCellValue(worksheetHandle,"F19",ExRConst_dataString,"不合格");
if(Test2Rst)
ExcelRpt_SetCellValue(worksheetHandle,"F20",ExRConst_dataString,"合格");
else
ExcelRpt_SetCellValue(worksheetHandle,"F20",ExRConst_dataString,"不合格");
if(Test3Rst)
ExcelRpt_SetCellValue(worksheetHandle,"F21",ExRConst_dataString,"合格");
else
ExcelRpt_SetCellValue(worksheetHandle,"F21",ExRConst_dataString,"不合格");
if(Test4Rst)
ExcelRpt_SetCellValue(worksheetHandle,"F22",ExRConst_dataString,"合格");
else
ExcelRpt_SetCellValue(worksheetHandle,"F22",ExRConst_dataString,"不合格");
//隨機(jī)生成曲線圖表用數(shù)據(jù)
for(int i=0;i<100;i++)
{
sprintf(index,"C%d",30+i);
sprintf(data,"D%d",30+i);
datavalue = rand()%100;
ExcelRpt_SetCellValue(worksheetHandle,index,ExRConst_dataInt,i);
ExcelRpt_SetCellValue(worksheetHandle,data,ExRConst_dataDouble,datavalue/10.0);
}
GetProjectDir(ExcelFileName);
strcat(ExcelFileName,NewRptFileName);
//報(bào)告按照新文件名報(bào)表
ExcelRpt_WorkbookSave(workbookHandle,ExcelFileName,ExRConst_DefaultFileFormat);
break;
}
return 0;
}
int CVICALLBACK btnExit (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event)
{
case EVENT_COMMIT:
if (worksheetHandle)
CA_DiscardObjHandle(worksheetHandle);
if (workbookHandle)
{
//退出程序前一定要釋放變量存儲(chǔ)
ExcelRpt_WorkbookClose(workbookHandle, 0);
CA_DiscardObjHandle(workbookHandle);
}
if (applicationHandle)
{
ExcelRpt_ApplicationQuit(applicationHandle);
CA_DiscardObjHandle(applicationHandle);
}
QuitUserInterface (0);
break;
}
return 0;
}
運(yùn)行程序,點(diǎn)擊“生成試驗(yàn)報(bào)告”按鈕,結(jié)果如下:

該程序使用簡(jiǎn)單,但也有不足:1.需要安裝office軟件;2.運(yùn)行速度較慢。后續(xù)將研究使用第三方控件獨(dú)立操作Excel文件。
這個(gè)例子的練習(xí)讓我又重新復(fù)習(xí)了很多C語(yǔ)言的知識(shí)。如整數(shù)轉(zhuǎn)字符、格式化字符、獲取系統(tǒng)時(shí)間、獲取一定范圍隨機(jī)數(shù)等。
歡迎交流QQ:491114509