C++Builder 6中开发 Office 程序心得

来源:互联网 发布:手机测音调软件 编辑:程序博客网 时间:2024/06/10 08:06

http://tech.ddvip.com/2008-09/122172092767012.html

一、用控件还是用OLEAutomation?

  这个问题应该说很常见。我也在任何可能的情况下坚持我的主张:用BCB 6提供的Server控件组。如果你是用Delphi 6/7版本开发,那么用Delphi提供的Server控件组。

  这样做有什么好处?我个人认为至少有如下两个:

  第一,维护结构化+OO的程序设计风格。例如:

ExcelApplication1->set_DisplayAlerts(0,false);
ExcelApplication1->Quit();

  又如:

int SheetCount=ExcelWorkbook1->Worksheets->Count;

  这些代码都还是比较直观的。而且很具有OO的美感。

  第二,强类型检查胜于弱类型检查。

  如果使用OleGetProperty或者OleSetProperty函数,那么对传递给这两个函数的参数,是没有办法控制的。例如,我完全可以随心设置一个单元格的属性FOO为100。但是这样的函数调用在运行期一定会出错。而使用Server控件就不会有这个问题——编译期就不能通过。可以在编译期发现并纠正的错误,不要留到运行期去解决。这是我的主张。

  二、必要的辅助手段

  使用BCB编写控制Excel的程序,是很繁琐的。因为有时编译通过后会出现难以琢磨的异常!又有一种很无助的感觉:BCB在这上面的帮助简直是BS。CodeInsight的速度又是相当的慢,无法忍受!

  不过,我们不要轻易放弃。根据我的经验,在BCB下要想好好掌握Excel编程,必须掌握三个获得帮助的途径。这三个获得帮助的途径就是(以我个人喜好的程度降序排列):

  Excel本身的宏命令。我现在的习惯是,如果我要在BCB中实现一个功能,但是却不知道相应的方法和参数,我就会打开Excel,在随便一个Sheet中用宏记录下我要进行的操作,然后研究宏代码。这样做,肯定能获得正确的方法名,但是对参数的数量和类型却不敢保证:这是因为VBA可以选择不PASS一些缺省参数。根据我的个人经验,这样做的有效性应该在80%左右,简易性在100%。

Office自带的VBA帮助。这个帮助在Office安装过程中一般不是缺省安装的。对于Office 2003中文版的用户,应该检查C:Program FilesMicrosoft OfficeOFFICE112052下是否有类似VBAxxnn.chm文件。其中xx应该是如下字符串之一:AC(Access),GR(Microsoft Graphics),OF(Office),OL(Outlook),OWS(Office Web Service),PB(Publisher),PP(PowerPoint),WD(Word),XL(Excel)。而nn是对应的Office应用的版本号。如果没有这些文件,请运行Office安装程序,在自定义安装中将这些文件安装即可。这些文件,对于我们理解Office应用中的DOM模型是非常有用的。其有效性为85%,简易性约为80%。

  BCB6中关于Server的头文件。这些头文件的位置应该是在:C:Program FilesBorlandCBuilder6IncludeVcl下。我这里只截一张图。从这张图中,我们也可以看到,BCB6对Office的支持只到Office 2000。Delphi 7可以支持到Office XP。不过它们都能很好的在Office 2003下工作。自Delphi 8之后,我们应该用Interop来操作Office了。这个方法的有效性是100%——因为你一定可以在里面找到BCB支持的方法,但是简易性只有10%——因为这些头文件都相当的大:excel_2k.h的大小是8M+!

C++Builder 6中开发 Office 程序心得(一)

  这三个手段应该互相帮衬,才能在更短的时间内找到正确的方法。而且通过这三个途径找到的方法、参数应该是互相对应、互相一致的。例如,移动一个Sheet到另一个Sheet的Move方法,其在上述三个帮助途径中的定义分别如下:

  在Excel的VBA宏里:Sheets("Sheet2").Move After:=Sheets(3)

Excel的VBA帮助:见下图

C++Builder 6中开发 Office 程序心得(一)

  BCB的Excel头文件:

// *********************************************************************//
// Interface: IWorksheets
// Flags: (4112) Hidden Dispatchable
// GUID: {000208B1-0001-0000-C000-000000000046}
// *********************************************************************//
interface IWorksheets : public IDispatch
{
public:
... ...
HRESULT STDMETHODCALLTYPE Copy(VARIANT Before/*[in,opt]*/= TNoParam(),
VARIANT After/*[in,opt]*/= TNoParam(),
... ...
HRESULT STDMETHODCALLTYPE Move(VARIANT Before/*[in,opt]*/= TNoParam(),
VARIANT After/*[in,opt]*/= TNoParam(),
long lcid/*[in]*/= TDefLCID()); // [637]
... ...

  三、编程指南

  (一) ExcelApplication的启动、退出

  我们平时所说的启动/退出Excel,在BCB6中应该被确切的说成是ExcelApplication的启动/退出。对应的控件是C++Builder 6中开发 Office 程序心得(一)。用来启动、退出的代码分别如下:

  void __fastcall TMainForm::EABtnClick(TObject *Sender)
{
try
{
EA->Connect();
}
catch(...)
{
ShowMessage("Can not launch server");
}
  EA->set_Caption((WideString)"Excel Server Invoked by BCB");
EA->set_Visible(0,true);
}
  __fastcall TMainForm::~TMainForm()
{
EA->set_DisplayAlerts(0,false);
EA->Quit();
}

  注意,Office控件多以接口形式互相关联,所以连接的方法也被贯之以Connect的名称。由于Excel Application一定是顶层对象,所以它的Connect方法不需要指定参数。

这样生成的Excel Application只是一个空架子。我们要增加Workbook(工作簿)。

  (二) ExcelWorkbook的创建和相关操作

  如果我们把ExcelWorkbook简单的理解为等价于一个xls文件,应该不会差别太大,而且应该对我们有帮助。它的控件图标是C++Builder 6中开发 Office 程序心得(一)。我们来看如何创建Workbook,代码如下:

  void __fastcall TMainForm::EWBBtnClick(TObject *Sender)
// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=1044&d=xr3888
{
EWB->ConnectTo(EA->Workbooks->Add(TNP, 0));
... ...
}

  首先,我们要连接到一个Workbook的接口上去,这里我们用的是新增一个Workbook的方式。注意TNP参数,我们会在很多场合使用它。它是我自己程序中定义的一个宏:

#define TNP TNoParam()

  而第二个参数0,则又是Locale ID(简称LID)。

  ExcelWorkbook还可以用来连接——或者说“打开”更恰当——一个现有的Workbook(一个xls文件),具体代码如下:

EWB->ConnectTo(EA->Workbooks->Open((WideString)"c:  emp  est.xls",
                 TNP, TNP, TNP, TNP,
                 TNP, TNP, TNP, TNP,
                 TNP, TNP, TNP, TNP, 0));

  上述代码中打开了位于c:temp下的test.xls文件。这个方法有很多参数,一般我都会传递TNP给它。具体参数的含义,可以参考相关文档。

(三) ExcelWorksheet的操作

  在上文连接Workbook的代码中,我也同时连接了TExcelWorksheet,其控件图标是C++Builder 6中开发 Office 程序心得(一)。所以完整的代码段如下:

  void __fastcall TMainForm::EWBBtnClick(TObject *Sender)
{
EWB->ConnectTo(EA->Workbooks->Add(TNP, 0));
// Connect to worksheet as well
EWS1->ConnectTo(EWB->Worksheets->get_Item(V("Sheet1")));
EWS2->ConnectTo(EWB->Worksheets->get_Item(V(2)));
  EWS3P=EWB->Worksheets->get_Item(V("Sheet3"));
EWS3->ConnectTo(EWS3P);
EWS3->Activate();
}

  我们知道,缺省情况下,一个空白的Excel Workbook有三个空白的Worksheet,所以上文中我用三个ExcelWorksheet控件来连接这三个Worksheet。

  我们既可以用表的名字(如“Sheet1”),也可以用表的序号(如“2”)来作为一个表的索引号。请注意V方法,它也是我定义的一个宏:

#define V TVariant

  所以,它只是一个用来构造TVariant参数的宏。它和上面的TNP宏都是蛮有用的定义。

  下面是一些针对Excel Worksheet的操作,不再一一详细说明。

  void __fastcall TMainForm::MoveSheetBtnClick(TObject *Sender)
{
EWS1->Move(TNP, V(EWB->Worksheets->get_Item(V("Sheet3"))), 0);
}
//---------------------------------------------------------------------------
  void __fastcall TMainForm::RenameBtnClick(TObject *Sender)
{
String NewName;
InputQuery("Rename Excel Worksheet", "Input a new name", NewName);
EWS1->set_Name((WideString)NewName);
}
//---------------------------------------------------------------------------
  void __fastcall TMainForm::CreateBtnClick(TObject *Sender)
{
EWS4->ConnectTo(EWB->Sheets->
Add(TNP,V(EWB->Worksheets->get_Item(V("Sheet3"))),V(1),V(xlWorksheet)));
}
//---------------------------------------------------------------------------
  void __fastcall TMainForm::DelSheetBtnClick(TObject *Sender)
{
EWS2->Delete(0);
}

  我们已经操作到了Worksheet级别,但是在我们日常操作中,接触最多的是Range(范围)和Cell(单元格),在后文我们将继续深入讨论,并讨论如何连接数据库、如何画数据图,以及如何用TExcelQueryTable加速数据导入的方法。

四) 单元格的操作

  单元格的操作实际上就是对范围(Range)的操作。一般的代码段如下:

RangePtr r;
r=EWS4->get_Range(V("a1"), V("a1"));
r->set_Value(V("Species No"));

  所以,对单元格内容的操作实际就是先获得一个要操作的范围(Range),然后再set_Value的过程。

ExcelWorksheet->Cells->set_Item(Variant(row),Variant(col),Variant(value.c_bstr()));

 

先选中一个RANGE,再插入一行.  
        AnsiString s_row="A"+IntToStr(row);
        RangePtr r=ExcelWorksheet1->get_Range(V(s_row),V(s_row))->Rows;
        r->EntireRow->Insert(V(1));


 

  和数据库连接并不很困难。将数据库中的数据写到Excel Worksheet中也不是很难,无非是遍历数据集,然后将对应字段的内容写到相应的单元格里去而已,所以这里我就不详细论述了。公式的输入也是如此。

  实际操作的效果如下图:

C++Builder 6中开发 Office 程序心得(二)

  这里需要说明两个地方。第一是字体和栏目宽度的调整。具体的代码如下:

r=EWS4->get_Range(V(CellRef), V(CellRef2));
r->Font->set_Name(V("Arial"));
r->get_Columns()->AutoFit();
r->set_WrapText(V(true));

  其操作流程也是先选择一个范围,然后设置字体名称、栏目宽度、自动换行等。

  第二是图形的显示。这需要多一些操作才可以:

  void __fastcall TMainForm::FillDataBtnClick(TObject *Sender)
{
unsigned int DataHandle;
HPALETTE APalette;
unsigned short MyFormat;
Graphics::TBitmap *Bitmap = new Graphics::TBitmap();
  ... ...
while (!Table1->Eof)
{
... ...
CellRef="e"+IntToStr(Count);
r=EWS4->get_Range(V(CellRef), V(CellRef));
Bitmap->Assign(Table1Graphic);
Bitmap->SaveToClipboardFormat(MyFormat,DataHandle,APalette);
Clipboard()->SetAsHandle(MyFormat,DataHandle);
EWS4->Paste(V(LPDISPATCH(r)), TNP, 0);
  ... ...
}
  ... ...
  delete Bitmap;
return;
}

  这里采用了Bitmap->Assign,将图形字段的内容作为Bitmap的内容,然后将Bitmap以剪贴板的格式保存到DataHandle中去,并返回保存的格式到MyFormat。然后用Clipbboard的SetAsHandle方法,将DataHandle中的内容以MyFormat格式“拷贝”到剪贴板上。最后,再用Worksheet的Paste方法将剪贴板上的图片拷贝到r指定的地方。

注意,r只是指明了被拷贝内容左上角的位置。对于图片来说,它不会、也不应该自动适应到一个单元格中。所以,在上述例子中,E列的宽度无法自动适应图片的宽度,需要另外调节。

  (五) 根据数据绘制图形

  图形在Office Server控件中是独立的,图标为:C++Builder 6中开发 Office 程序心得(二)。操作它的代码一般如下:

  void __fastcall TMainForm::DrawBtnClick(TObject *Sender)
// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=1045&d=6375g6
{
RangePtr r=EWS4->get_Range(V("b1"), V("c"+IntToStr(Count-1)));
  EC->ConnectTo(EWB->Sheets->Add(TNP, TNP, V(1), V(xlChart),0));
EC->set_ChartType(xlColumnClustered);
EC->SetSourceData(r, V(xlColumns));
  //Set Titles
EC->ChartTitle[0]->set_Caption((WideString)"Animal Data Report");
EC->set_Name((WideString)"Animal Data Chart");
EC->set_HasDataTable(true);
EC->set_HasLegend(0,false);
}

  这里的ChartType可用的enum变量可以在帮助文件中获得。在这里,我碰到了难题。因为我不知道如何设置X/Y轴的标题。虽然我可以编写代码使编译通过,但是在运行时一定出错。我已经无计可施,也不想继续下功夫了——因为我想转换到Interop下去编程。

  (六) 使用TExcelQueryTable

  (四)中介绍的将数据库中的数据导入Excel Worksheet的方法是很慢的。第一,遍历数据集很花费时间;第二,频繁的对单元格进行操作也很花时间。所以,需要用一个改进了的控件来加快大量数据的导入。

 

  这个控件就是TExcelQueryTable,图标是C++Builder 6中开发 Office 程序心得(二)。其典型代码如下:

  void __fastcall TMainForm::Button1Click(TObject *Sender)
{
String ConnStr;
RangePtr R;
String SQL;
  EWS1->Activate();
ConnStr="ODBC;DSN=testdbf;UID='';PWD=''";
SQL="select * from animals";
R=EWS1->get_Range(V("a1"), V("a1"));
  EQT->ConnectTo(EWS1->QueryTables->Add(V(ConnStr), R, V(SQL)));
EQT->Refresh();
}

  使用ExcelQueryTable要至少三个参数。

  ConnectionString。它用来连接到一个数据库。在上例中我采用的是ODBC方式。用OLE DB也是可以的。

  SQL。它用来返回一个记录集。

  Range。它指定了记录集从哪个单元格开始填充。从左到右各列将代表记录集的字段;从上到下就是各个记录。

  用这个方式填充大量数据,可以大幅度的提升速度。

  关于用BCB 6操作Excel的介绍就此打住。希望给大家一些帮助。

 

//--------------------------一个例子:再WinXP 和bcb6下测试通过

Excel.h//---------------------------------------------------------------------------

#ifndef ExcelH
#define ExcelH

#define TNP TNoParam()
#define V TVariant
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <DBGrids.hpp>
#include <Grids.hpp>
#include <OleServer.hpp>

#include "TTF160_OCX.h"
#include "Excel_2K_SRVR.h"
#include <ADODB.hpp>
#include <DB.hpp>

//---------------------------------------------------------------------------
class TMainExcel : public TDataModule
{
__published:    // IDE-managed Components
        TExcelApplication *ExcelApplication1;
        TExcelWorkbook *ExcelWorkbook1;
        TExcelWorksheet *ExcelWorksheet1;
        TExcelQueryTable *ExcelQueryTable1;
        TADOQuery *dataSet;
private:    // User declarations
        WideString cs_filename;
public:        // User declarations
        __fastcall TMainExcel(TComponent* Owner);
        void WriteToExcelWorksheet(TExcelWorksheet * ExcelWorksheet,int row,int col,WideString value);
        void addRow(TExcelWorksheet * ExcelWorksheet1,int row);
        void deleteRow(TExcelWorksheet * ExcelWorksheet1,int row);
        void ExcelFilePrint(WideString filename);
        void DBGridToExcelPrint(TList * dsList,WideString xlsname);
        void FormulaoneSaveToExcel(TF6Book * formulaone);
        void FormulaSaveAsExcelAuto(TF6Book * formulaone);
        void FormulaoneToExcelPrint(TF6Book * formulaone);
};
//---------------------------------------------------------------------------
extern PACKAGE TMainExcel *MainExcel;
//---------------------------------------------------------------------------
#endif

 

Excel.cpp

//--------------------------------------------------------------------------


//这三句必须添加。否则debug可以通过,release不能通过

#define   NOWIN32_LEAN_AND_MEAN
#include   <shlobj.hpp>
#include   <vcl.h>

 

#pragma hdrstop

#include "Excel.h"

#include <utilcls.h>
#include "untdata.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "TTF160_OCX"
#pragma link "Excel_2K_SRVR"
#pragma resource "*.dfm"

TMainExcel *MainExcel;
//---------------------------------------------------------------------------
__fastcall TMainExcel::TMainExcel(TComponent* Owner)
        : TDataModule(Owner)
{
        cs_filename=WideString(ExtractFilePath(Application->ExeName)+"print.xls");
}
//--------------------------------------------------------------------------
void TMainExcel::WriteToExcelWorksheet(TExcelWorksheet * ExcelWorksheet,int row,int col,WideString value)
{
        ExcelWorksheet->Cells->set_Item(Variant(row),Variant(col),Variant(value.c_bstr()));
}
//在row行上添加一行
void TMainExcel::addRow(TExcelWorksheet * ExcelWorksheet1,int row)
{
        WideString s_row="A"+IntToStr(row);
        RangePtr r=ExcelWorksheet1->get_Range(V(s_row),V(s_row))->Rows;
        r->EntireRow->Insert(V(1));
}
void TMainExcel::deleteRow(TExcelWorksheet * ExcelWorksheet1,int row)
{
        AnsiString s_row="A"+IntToStr(row);
        RangePtr r=ExcelWorksheet1->get_Range(V(s_row),V(s_row))->Rows;
        r->EntireRow->Delete(V(1));
}
//---------------------------------------------------------------------------
/*
        *io TList dsList (TADOQuery 列表);
        xlsname 不带路径不带扩展名
*/
void TMainExcel::DBGridToExcelPrint(TList * dsList,WideString xlsname)
{
        TADOQuery * dataSet,*tableExcel;
        int iRow,iCol,iLjhh,inc;
        String strSQL,strFieldName,strTableName;
        WideString xlspath=ExtractFilePath(Application->ExeName)+"TableData//"+xlsname+".xls";
        if(!FileExists(xlspath))
        {
                ShowMessage("缺少xls模板文件!");
                return;
        }
        if(dsList->Count<0)
        {
                ShowMessage("没有正确的数据集合!");
                return;
        }
        //打开xls文件
        OleVariant ItemIndex = 1;
        try
        {
                this->ExcelApplication1->Connect();
        }
        catch(...)
        {
                MessageDlg("没有安装Excel!",mtError,TMsgDlgButtons()<<mbYes,0);
                Abort();
        }
        ExcelApplication1->GetDefaultInterface()->set_Visible(0,true);
        ExcelApplication1->set_Caption(StringToOleStr("打印申报表"));

        ExcelApplication1->Workbooks->Open(StringToOleStr(xlspath),TNP, TNP, TNP, TNP,TNP, TNP, TNP, TNP,TNP, TNP, TNP, TNP,0);
        ExcelWorkbook1->ConnectTo(ExcelApplication1->Workbooks->get_Item(ItemIndex));

        ExcelWorksheet1->ConnectTo(ExcelWorkbook1->Worksheets->get_Item(ItemIndex));

        //写入动态数据
        dsList->First();
        for(int i=0;i<dsList->Count;i++)
        {
                dataSet=(TADOQuery *)dsList->operator [](i);
                dataSet->First();
                inc=0;
                tableExcel=new TADOQuery(this);
                AnsiString sql="select * from TableExcel where Pname='"+AnsiString(xlsname)+"' and IsHJ=0 and TRead=Yes  and Tableorder="+IntToStr(i+1)+"  and TLJHH=0 order by prow,pcol";
                MainData->PsqlResult(tableExcel,sql);
                if(tableExcel->RecordCount<1) //if TLJHH=0 代表是存在记录列表,>0则代表特定号码的记录
                {
                        tableExcel->First();
                        while(!dataSet->Eof)
                        {
                                sql="select * from TableExcel where Pname='"+AnsiString(xlsname)+"' and IsHJ=0 and TRead=Yes  and Tableorder="+IntToStr(i+1)+"  and TLJHH="+dataSet->FieldByName("LJHH")->AsString+" order by prow,pcol";
                                MainData->PsqlResult(tableExcel,sql);
                                //每条记录写入Excel
                                while(!tableExcel->Eof)
                                {
                                        //表名和逻辑号码 没有用到
                                        //strTableName=tableExcel->FieldByName("tname")->AsString;

                                        strFieldName=tableExcel->FieldByName("TfieldName")->AsString;
                                        //iLjhh       =tableExcel->FieldByName("TLJHH")->AsInteger;
                                        iRow        =tableExcel->FieldByName("PRow")->AsInteger;
                                        iCol        =tableExcel->FieldByName("PCol")->AsInteger;
                                        WriteToExcelWorksheet(ExcelWorksheet1,Variant(iRow+inc),Variant(iCol+inc),Variant(dataSet->FieldByName(strFieldName)->AsString.c_str()));
                                        //设置Excel单元格数据
                                        //获得累计数---Excel 文件自动计算
                                        tableExcel->Next();
                                }
                                //Excel 增加一行
                                inc++;
                                addRow(ExcelWorksheet1,iRow+inc);
                                dataSet->Next();
                        }
                }
                else
                {
                        tableExcel->First();
                        while(!dataSet->Eof)
                        {
                                //每条记录写入Excel
                                while(!tableExcel->Eof)
                                {
                                        //表名和逻辑号码 没有用到
                                        //strTableName=tableExcel->FieldByName("tname")->AsString;
                                        strFieldName=tableExcel->FieldByName("TfieldName")->AsString;
                                        //iLjhh       =tableExcel->FieldByName("TLJHH")->AsInteger;
                                        iRow        =tableExcel->FieldByName("PRow")->AsInteger;
                                        iCol        =tableExcel->FieldByName("PCol")->AsInteger;
                                        WriteToExcelWorksheet(ExcelWorksheet1,Variant(iRow+inc),Variant(iCol+inc),Variant(dataSet->FieldByName(strFieldName)->AsString.c_str()));
                                        //设置Excel单元格数据
                                        //获得累计数---Excel 文件自动计算
                                        tableExcel->Next();
                                }
                                //Excel 增加一行
                                inc++;
                                addRow(ExcelWorksheet1,iRow+inc);
                                dataSet->Next();
                        }
                }
                //删除最后多加的一行
                deleteRow(ExcelWorksheet1,iRow+inc);
        }
        ExcelWorksheet1->PrintPreview(TNP,0);

        ExcelApplication1->set_DisplayAlerts(0,false);
        ExcelApplication1->Quit();
        delete tableExcel;
}
void TMainExcel::ExcelFilePrint(WideString filename)
{
        OleVariant ItemIndex = 1;
        try
        {
                this->ExcelApplication1->Connect();
        }
        catch(...)
        {
                MessageDlg("没有安装Excel!",mtError,TMsgDlgButtons()<<mbYes,0);
                Abort();
        }
        ExcelApplication1->GetDefaultInterface()->set_Visible(0,true);
        ExcelApplication1->set_Caption(StringToOleStr("打印申报表"));

        ExcelApplication1->Workbooks->Open(StringToOleStr(filename),
                                  TNP, TNP, TNP, TNP,TNP, TNP, TNP, TNP,TNP, TNP, TNP, TNP,0);
        ExcelWorkbook1->ConnectTo(ExcelApplication1->Workbooks->get_Item(ItemIndex));

        ExcelWorksheet1->ConnectTo(ExcelWorkbook1->Worksheets->get_Item(ItemIndex));

        ExcelWorksheet1->PrintPreview(TNP,0);

        ExcelApplication1->set_DisplayAlerts(0,false);
        ExcelApplication1->Quit();
}
//------------------------------------------------------------------
void TMainExcel::FormulaoneSaveToExcel(TF6Book * formulaone)
{
  WideString ls_buf="";
  WideString tishi="请选择文件夹及输入文件名";
  short li_mode=11; //文件类型Excel97=11

  try{
    formulaone->SaveFileDlg(tishi.c_bstr(),&ls_buf,&li_mode);
  }
  catch(...){
  }
  //如果 点击取消那么 保存文件名为空,保存模式为18
  if (!ls_buf.IsEmpty() && li_mode!=18 ){
    try{
      formulaone->WriteEx(ls_buf,li_mode);
      ShowMessage("保存成功。/n表格被保存在"+ls_buf+"中。");
    }
    catch(Exception &e){
      ShowMessage("保存失败。"+e.Message);
    }
  }       
}
//自动保存到当前目录下的print.xls 2009-03-17   Yanfl   返回自动保存的文件名
void TMainExcel::FormulaSaveAsExcelAuto(TF6Book * formulaone)
{

  WideString tishi="请选择文件夹及输入文件名";
  short li_mode=11; //文件类型Excel97=11
  if(FileExists(cs_filename))
  {
        DeleteFile(cs_filename.c_bstr());
  }
  //如果 点击取消那么 保存文件名为空,保存模式为18
  if (!cs_filename.IsEmpty() && li_mode!=18 ){
    try{
      formulaone->WriteEx(cs_filename,li_mode);
    }
    catch(Exception &e){
      ShowMessage("临时文件生成失败。"+e.Message);
    }
  }
}
//--------------------------------------------------------------
void TMainExcel::FormulaoneToExcelPrint(TF6Book * formulaone)
{
        //保存为临时xls文件
        this->FormulaSaveAsExcelAuto(formulaone);
        //打印临时文件
        if(FileExists(cs_filename))
        {
                this->ExcelFilePrint(cs_filename);
        }
        else
                ShowMessage("打印临时文件成成失败");
}