`
yaasshole
  • 浏览: 662380 次
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

Excel 开发文档

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

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

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

最后一行 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/l ocal/sampleexecutables/Technologies/Interop/Applications/Office/Excel.zip

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

Excel Application 对象

概念

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

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

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

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

示例

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

C# 代码

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

请注意下面的代码:

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 支持,如下图:

源代码如下:

#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 技术可以让我们的生活更加轻松许多。

Work b ooks Work b ook 对象

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

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

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

创建一个空 Work b ook 对象

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 枚举类型 的值 指定了 要创建的 Workb ook的类型。

xlWBATChart 代表 Chart.

xlWBATExcel IntlMacroSheet 代表 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<< <!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->CWindowsError::getOfficeError(hr)<<endl;

return 1;

}

_WorkbookPtr workbook=createWorkbook(ptr);

ptr->PutVisible (0,VARIANT_TRUE);

hr=ptr->Quit();

if (FAILED(hr))

{

<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -- --> 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()));

}

WorkSheets WorkSheet 对象

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

这里有 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 G etValue( Worksheet sheet, int row, int col)

{

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

return cell.Text.ToString();

}

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

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

static void S etValue( 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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics