Excel开发入门(C#和C++实例)

时间:2022-05-06 05:36:21

 

Excel开发文档

              这篇文章的例子采用Office 2003英文版。首先打开一个Excel2003程序,然后选择菜单HelpMicrosoft Excel Help,如下图:

Excel开发入门(C#和C++实例)

              这样,右边会出现一个帮助子窗口,如下:

Excel开发入门(C#和C++实例)

              选择Table of Contents,会出现下图。

Excel开发入门(C#和C++实例)

              最后一行Microsoft Excel Visual Basic Reference就是我们要找的文档。该文档基本描述了Excel的主要对象的属性和方法。

 

              如果你安装了MSDN FOR VS.NET 2005英文版,你可以在下面的地址找到Excel的例子程序:

ms-help://MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_fxsamples/local/sampleexecutables/Technologies/Interop/Applications/Office/Excel.zip

              MSND也包含了一个专题:Office Solutions Development

ExcelApplication对象

概念

              Application对象代表的是Excel程序。为了更好的理解Application是什么,我们可以先启动一个Excel程序,然后选择菜单栏最右边的关闭按钮,这样就可以关掉默认创建的空文档对象。现在出现在我们眼前的就是Application对象:

Excel开发入门(C#和C++实例)

 

              Excel是一个MDI程序。MDIMutiple Document Interface多文档界面)怎么理解呢?

熟悉微软历史悠久的MFC开发知识的程序员就知道:每一个MDI窗口应用程序都有一个主框架窗口,主框架窗口可以拥有多个子框架窗口,每个子框架窗口管理一个Document对象(文档对象负责管理数据)和一个View对象(视图对象负责显示数据,接受用户事件)。实际上后来MDI概念只是代表一种风格,即一个主框架窗口允许同时显示多个子窗口,是否有Document对象已经不重要。

              现在我们可以清楚地知道ExcelApplication对象就代表了MDI风格窗口的主框架。

示例

              示例的目的是描述如何使用多种语言来创建一个Excel程序。为了简化篇幅,如何使用IDE的内容不作详细描述。

C#代码

              首先创建一个C#Console工程。我这里使用的总是Visual Studio.net 2005英文版。然后右键选择工程,选择Add Reference,在弹出的对话框中选择COM一栏,选中如下的组件:

Excel开发入门(C#和C++实例)

请注意下面的代码:

using System.Reflection; // For Missing.Value and BindingFlags

using System.Runtime.InteropServices; // For COMException

using Microsoft.Office.Interop.Excel;

 

namespace ExcelApplicationSample

{

    class Program

    {

        static void Main(string[] args)

        {

            try

            {

                Application app = new Application();

                app.Visible = true;

                app.Quit();

                                            app=null;//这句话可以使垃圾回收器关闭Excel进程

            }

            catch (COMException e)

            {

                Console.WriteLine(e.Message);

            }

        }

    }

}

              Application app = new Application();创建了一个Excel的Application对象。app.Visible = true;设置窗口状态为显示。app.Quit();关闭Application对象。注意,如果出错会抛出COMException异常。如果我们将断点放在app.Quit()这一行,我们会看到程序会打开一个只有主框架的Excel程序。就像前面的图示一样。

C++代码

              创建一个Win32 Console工程ExcelApplicationSampleCPlus。然后选择添加ATL支持,如下图:

              Excel开发入门(C#和C++实例)

             

              源代码如下:

 

#include "stdafx.h"

#include

using namespace std;

 

#import "C:Program FilesCommon FilesMicrosoft SharedOFFICE11mso.dll" rename("RGB", "MSRGB")

 

#import "C:Program FilesCommon FilesMicrosoft SharedVBAVBA6VBE6EXT.OLB" 

rename("Reference", "ignorethis"), rename("VBE", "JOEVBE")

 

#import "C:Program FilesMicrosoft OfficeOFFICE11excel.exe" exclude("IFont", "IPicture")

rename("RGB", "ignorethis"), rename("DialogBox", "ignorethis"), rename("VBE", "JOEVBE"),

rename("ReplaceText", "JOEReplaceText"), rename("CopyFile","JOECopyFile"),

rename("FindText", "JOEFindText"), rename("NoPrompt", "JOENoPrompt")

 

using namespace Office;

using namespace VBIDE;

using namespace Excel ;

 

#include "WindowsError.h"

 

 

class AppartmentWrapper

{

public:

              AppartmentWrapper()

              {

                            ::CoInitialize(NULL);

              }

 

              ~AppartmentWrapper()

              {

                            ::CoUninitialize();

              }

};

 

 

int _tmain(int argc, _TCHAR* argv[])

{

              try

              {

                            AppartmentWrapper appartment;

                            _ApplicationPtr ptr=NULL;

                            HRESULT hr=ptr.CreateInstance("Exce2l.Application");

                            if(FAILED(hr))

                            {

                                          cout<<

                                          return 1;

                            }

                            ptr->PutVisible (0,VARIANT_TRUE);

                            hr=ptr->Quit();

                            if(FAILED(hr))

                            {

                                          cout<<

                                          return 1;

                            }

              }

              catch(_com_error const& e)

              {

                            cout<<

                            return 1;

              }

              return 0;

}

 

              VC++的代码要比C#复杂得多,主要在于:

  1. 引入组件库的时候需要重命名一些类,避免重名
  2. 错误信息的获取没有C#COMException异常对象来支持,需要自己处理。CWindowsError::getOfficeError方法是我自己花了一个小时才编写好的。代码如下:

#pragma once

 

#include

#include

 

class CWindowsError

{

public:

              static std::string getLastError()

              {

                            char szBuf[80];

                            void* lpMsgBuf=NULL;

                            DWORD dw = GetLastError();

 

                            FormatMessageA(

                                          FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,

                                          NULL,

                                          dw,

                                          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),

                                          (char*) &lpMsgBuf,

                                          0,

                                          NULL);

 

 

                            wsprintfA(szBuf, "error %d: %s",dw, lpMsgBuf);

 

                            LocalFree(lpMsgBuf);

                            return szBuf;

              }

 

              static std::string getOfficeError(HRESULT hr)

              {

                            char buf[256]={0};

                            FormatMessageA(

                                          FORMAT_MESSAGE_FROM_SYSTEM,

                                          NULL,

                                          hr,

                                          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),

                                          &buf[0],

                                          256,

                                          NULL);

                            std::stringstream stream;

                            stream<<"error "<


<<
": " <

                            return stream.str();

              }

};

  1. 另外你需要对COM有所了解,这点对很多VC程序员难度都不小。

              由于.Net是通过Interop方式间接调用Office组件(整个Office程序都是由COM组件编写的),因此比起C++直接调用IDispatch接口方式要慢得多。不过一般情况下,使用Office的程序性能要求不会很苛刻,.Net技术可以让我们的生活更加轻松许多。

             

WorkbooksWorkbook对象

              WorkBook对象代表了一个Excel程序可以打开的一个工作簿。如下图中标题为Book1的子窗口就是一个Workbook对象。

Excel开发入门(C#和C++实例)

 

              由于ExcelMDI程序,所以可以同时打开多个WorkBook对象作为子窗口。如下图中的Book1Book2窗口。

Excel开发入门(C#和C++实例)

 

              代表框架窗口的Application对象管理着WorkBooks对象,WorkBooks对象是WorkBook对象的集合。

 

创建一个空Workbook对象

C#代码

              我们对前面的C#代码进行了一些修改,代码如下:

    class Program

    {

        static void Main(string[] args)

        {

             Application app=null;

            try

            {

                app = new Application();

                Workbook book=CreateDocument(app);

                app.Visible = true;

            }

            catch (COMException e)

            {

                Console.WriteLine(e.Message);

            }

            finally

            {

                app.Quit();

            }

        }

 

        static Workbook CreateDocument(Application app)

        {

            return app.Workbooks.Add(XlWBATemplate.xlWBATWorksheet);

        }

    }

              注意CreateDocument方法的实现代码XlWBATemplate枚举类型的值指定了要创建的Workbook的类型。

xlWBATChart 代表Chart.

xlWBATExcelIntlMacroSheet 代表Excel version 4 macro.

xlWBATExcel4MacroSheet 代表Excel version 4 international macro.

xlWBATWorksheet 代表Worksheet.

              Worksheet的概念下面一个章节会讲到,这里需要知道的是当创建一个WorkBook对象的时候,总是会自动创建一个Worksheet对象。

C++代码

             

_WorkbookPtr createWorkbook(_ApplicationPtr app)

{

              WorkbooksPtr books=app->GetWorkbooks();

              _variant_t v(xlWorksheet);

              return books->Add(v);

}

 

 

int _tmain(int argc, _TCHAR* argv[])

{

              try

              {

                            AppartmentWrapper appartment;

                            _ApplicationPtr ptr=NULL;

                            HRESULT hr=ptr.CreateInstance("Excel.Application");

                            if(FAILED(hr))

                            {

                                          cout<< CWindowsError::getOfficeError(hr)<<endl;

                                          return 1;

                            }

                            _WorkbookPtr workbook=createWorkbook(ptr);

                            ptr->PutVisible (0,VARIANT_TRUE);

                            hr=ptr->Quit();

                            if(FAILED(hr))

                            {

                                   cout<<CWindowsError::getOfficeError(hr)<<endl;

 

                                          return 1;

                            }

              }

              catch(_com_error const& e)

              {

                            cout<<CWindowsError::getOfficeError(hr)<<endl;

                            return 1;

              }

              return 0;

}

 

C++中的Workbook类型的枚举定义为:

enum XlSheetType

{

    xlChart = -4109,

    xlDialogSheet = -4116,

    xlExcel4IntlMacroSheet = 4,

    xlExcel4MacroSheet = 3,

    xlWorksheet = -4167

};

打开一个已经存在的WorkBook对象

C#代码

        static Workbook OpenDocument(Application app, String fileName)

        {

            return app.Workbooks.Open(fileName, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,

                Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,Type.Missing, Type.Missing);

        }

C++代码

_WorkbookPtr openWorkbook(_ApplicationPtr app,string const& fileName)

{

              WorkbooksPtr books=app->GetWorkbooks();

              return books->Open(_bstr_t(fileName.c_str()));

}

WorkSheetsWorkSheet对象

              每一个Workbook对象都拥有一个或者多个Worksheet对象。每个Worksheet对象代表了一张表格。如下图:

Excel开发入门(C#和C++实例)

              这里有Sheet1,Sheet2,Sheet3三张表格,他们都是Worksheet对象。当前的Workbook对象代表了这个子窗口,并且用有成员Worksheets对象。Worksheets对象是三个Worksheet对象的集合。

 

读取某表格实际使用的行数和列数

              Worksheet sheet = (Worksheet)book.Sheets["Sheet1"];

     int rowCount=sheet.UsedRange.Rows.Count;

     int colCount = sheet.UsedRange.Columns.Count;

读取某表格指定位置的数据

                  static String GetValue(Worksheet sheet, int row, int col)

        {

            Range cell=(Range)sheet.UsedRange.Cells[row, col];

            return cell.Text.ToString();

        }

注意,行和列的索引总是从1开始。

改写某表格指定位置的数据

                  static void SetValue(Worksheet sheet, int row, int col,String value)

        {

            Range cell = (Range)sheet.UsedRange.Cells[row, col];

            cell.Value2 = value; ;

        }

插入行到某表格中

                  // 插行(在指定WorkSheet指定行上面插入指定数量行)

        static void InsertRows(Excel.Worksheet wst, int rowIndex, int count)

        {

            Excel.Range range = (Excel.Range)wst.Rows[rowIndex, Type.Missing];

 

            for (int i = 0; i < count; i++)

            {

                range.Insert(Excel.XlDirection.xlDown, Type.Missing);

            }

        }

 

 

5