PLM之家PLMHome-工业软件践行者

[转载电子书] VS2010 C++ 操作Excel表格的编程实现

[复制链接]

2014-11-10 15:54:05 5810 0

请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!

您需要 登录 才可以下载或查看,没有账号?注册

x
通过VC实现对Excel表格的操作的方法有多种,如:通过ODBC数据库实现,通过解析Excel表格文件,通过OLE/COM的实现。本文主要研究通过OLE/COM实现对Excel表格的操作。
0 d  f8 T! z* m8 L2 ^3 @
# j( S5 k6 T3 |2 s
! y7 D+ \6 e: n/ P
1、添加OLE/COM支持。
首先,应用程序必须添加对OLE/COM的支持,才能导入OLE/COM组件。
本文使用的是MFC对话框程序,在创建工程的向导中选中Automation选项即可为程序自动添加相应的头文件和OLE库初始化代码。
通过查看源代码,可以知道在stdafx.h的头文件中,添加了OLE/COM很多类所需添加的头文件。
#include <afxdisp.h>        // MFC 自动化类
同时,在应用程序类的InitInstance函数中,添加了OLE/COM的初始化代码,如下所示:
// 初始化 OLE 库
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
; u- D& |% B5 F$ r
2、导入并封装Excel中的接口
Excel作为OLE/COM库插件,定义好了各类交互的接口,这些接口是跨语言的接口。VC可以通过导入这些接口,并通过接口来对Excel的操作。
由于本文只关心对Excel表格中的数据的读取,主要关注几个_Application、Workbooks、_Workbook、Worksheets、_Worksheet、Range等几个接口。Excel的各类接口的属性、方法可以通过MSDN的Office Development进行查询。
VS2010导入OLE/COM组件的接口的步骤为:Project->Class Wizard->Add Class->MFC Class From TypeLib,先选择要导入的组件所在的路径,即Excel.exe所在的路径,然后再选择
要导入的Excel类型库中的接口。
在完成接口导入后,VS2010将自动为导入的接口创建相应的实现类,用于对接口属性和方法的实现。由于标准的C++没有属性访问器,只能添加一个两个存取函数来实现对属性的访问,通过在属性名称前加上get_和put_前缀分别实现对属性的读写操作。即,由VC自动完成C++类对接口的封装。

3 W! u) N7 t) f+ f
本文所导入的接口对应的类和头文件的说明如下所示:

0 A  {' A$ _7 E6 e
Excel接口
导入类
头文件
说明
_Application
CApplicaton
Application.h
Excel应用程序。
Workbooks
CWorkbooks
Workbooks.h
工作簿的容器,里面包括了Excel应用程序打开的所有工作簿。
_Workbook
CWorkbook
Workbook.h
单个工作簿。
Worksheets
CWorksheets
Worksheets.h
单个工作簿中的Sheet表格的容器,包括该工作簿中的所有Sheet。
_Worksheet
CWorksheet
Worksheet.h
单个Sheet表格。
Range
CRange
Range.h
一定数量的单元格,可对单元格进行单个或多个单元格进行操作。
5 S, V2 v# m' ~0 q

. p, T" O9 x* I) A: g
3、导入Excel的整个类型库
接口对应类只是对接口的属性和方法进行了封装,而Excel中的数据类型,如枚举类型却并为并不能使用,因此,为了更方便的操作Excel,还需要导入Excel的数据类型。
通过查看导入接口对应的头文件可以发现,在所有导入接口的头文件中,都会有这么行:
#import "D:\\Program Files\\Microsoft Office\\Office12\\EXCEL.EXE" no_namespace
这行代码的作用是导入Excel整个类型库到工程中。
由VS2010自动产生的导入代码存在以下几个问题:
(1)如果导入了多个接口,每个头文件都会把类型库导入一次,如果引用多个头文件,会导致类型库重复导入。
(2)Excel类型库中有些类型会跟MFC类库的某些类型冲突。
(3)Excel类型库的某些类型跟其他Office和VB的某些库相关,如果不导入相关库,将导致这些类型无法使用。。
以上三点问题的解决方法如下:
(1)仅在_Application接口对应头文件中导入Excel类型库。
(2)对冲突的类型进行重命名。
(3)在导入Excel类型库之前,先导入Office和VB的相关库。
更改后的导入类型库的代码如下:

1 e1 G. t/ M5 ?3 D( T' h, L6 q
/*导入Office的类型库*/
#import "C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE12\\MSO.DLL" \
rename("RGB", "MSORGB") \
rename("DocumentProperties", "MSODocumentProperties")
using namespace Office;
5 P' g/ d0 w# V' d
/*导入VB的类型库*/
#import "C:\\Program Files\\Common Files\\Microsoft Shared\\VBA\\VBA6\\VBE6EXT.OLB"
using namespace VBIDE;
9 y9 ~) S$ c$ }7 O0 l
/*导入Excel的类型库*/
#import "D:\\Program Files\\Microsoft Office\\Office12\\EXCEL.EXE" \
rename("DialogBox", "ExcelDialogBox") \
rename("RGB", "ExcelRGB") \
rename("CopyFile", "ExcelCopyFile") \
rename("ReplaceText", "ExcelReplaceText") \
no_auto_exclude
Using namespace Excel;
- c$ R7 R! K: u, ~0 g: g1 h
编译程序后,会在DebUG或Release目录下生成三个文件mso.tlh、vbe6ext.tlh和excel.tlh。通过打开文件可知,该三个文件的命名空间分别是Office、VBIDE和Excel。导入了Excel的整个类型库后,就可以使用Excel中的所有类型了。
% v( z7 c, |% x2 g1 \7 M3 i1 i
4、操作Excel步骤
操作Excel的主要步骤如下:
(1)创建一个Excel应用程序。
(2)得到Workbook的容器。
(3)打开一个Workbook或者创建一个Workbook。
(4)得到Workbook中的Worksheet的容器。
(5)打开一个Worksheet或者创建一个WorkSheet。
(6)通过Range对WorkSheet中的单元格进行读写操作。
(7)保存Excel。
(8)释放资源。
( @, W! L6 V. w$ m0 I2 n6 ^
5、批量处理Excel表格
VC通过OLE/COM操作Excel,是通过进程间的组件技术。因此,每次读写Excel中的单元格时,都要进行进程间的切换。当数据量大,如果一个单元格一个单元格的读取,主要的时间都花费在进程切换中。因此读取多个单元格,将可有效的提高程序的运行效率。
对多个单元格的读写操作可以通过CRange中以下两个成员函数来完成。
VARIANT get_Value2();
void put_Value2(VARIANT& newValue);
其中,输入参数newValue只要输入一个二维数组,即可实现向Excel中一次写入多个单元格的值。
其中,VARIANT中实现二维数据的方法可参考
当然,在对CRange类进行操作之前,要设置CRange类对应的单元格。
2 Y9 E. h9 [( [! [( k! _9 h: v
6、Excel表格的保存
(1)如果要保存打开的工作簿,使用CWorkbook类的Save函数就可以保存工作簿,原文件将被覆盖。
(2)如果是新创建的工作簿,或者是要另存为,可使用CWorkbook类的SaveAs函数。
SaveAs的参数比较多。其中,第1个参数是设置要保存文件的路径;第2个参数是设置文件的格式,可在MSDN中查看枚举类型XlFileFormat来了解Excel的文件格式。经过测试,在本文所用的测试环境中,Excel2003的文件格式是xlExcel8,Excel2007的文件格式是xlExcel4。

+ g) d' d8 f- [. C7 j
7、获取当前Excel的版本
可以通过CApplication的get_Version函数来获得Excel的版本,其中,Excel2007的主版本号是12,Excel2003的主版本号是11。

( d4 w  N- W$ O
m_LisTCtrl.SetExtendedStyle(LVS_REPORT | LVS_EX_FULLROWSELECT);
- n5 V9 ]5 [: F1 f& @
2 {6 M6 g: C1 Y* K7 P    CApplication ExcelApp;
* s6 f- i+ K1 _( I1 @    CWorkbooks books;# g5 T& P, b4 d
    CWorkbook book;: Y* q! X( A9 I0 M* T: b  g3 R
    CWorksheets sheets;' k; [3 A; g  L5 R" k( f; K3 E
    CWorksheet sheet;
& B# Q" I! b% I5 E* s, @8 y    CRange range;/ D& z( @5 p# k. C+ Q4 D- ^+ a
    LPDISPATCH lpDisp = NULL;6 G, q7 S+ {7 M) y

2 B5 ~* }$ I# g    //创建Excel 服务器(启动Excel)
# u8 R: w8 c) F& M    if(!ExcelApp.CreateDispatch(_T("Excel.Application"),NULL))
6 D) Y' {" l. D# f    {0 n4 b; t; f5 Y( {
        AfxMessageBox(_T("启动Excel服务器失败!"));" x: o7 k: K8 g) H& w. Q
        return -1;3 ~) V2 X1 O+ K( R
    }3 n. O1 G3 U5 p* m7 q
/ t. q/ m) F" c8 C7 r
    /*判断当前Excel的版本*/
9 X) Z  }2 H5 `1 I    CString strExcelVersion = ExcelApp.get_Version();
! c3 B# r5 U4 ~    int iStart = 0;1 V( I& p8 _. m6 s4 Q# H2 n8 w
    strExcelVersion = strExcelVersion.Tokenize(_T("."), iStart);
% z0 o- r' b9 p# z    if (_T("11") == strExcelVersion)' Q2 p. j! W  ?) t
    {. j4 {& l5 p* Q4 z1 P
        AfxMessageBox(_T("当前Excel的版本是2003。"));
, p8 {  y* h% w1 Y" \7 H$ V: v% W    }
  k4 {7 p' g0 M! v0 r" h0 Z! e% k; w    else if (_T("12") == strExcelVersion)' [$ _* B! v1 {
    {
' x, u" b, P) J" a        AfxMessageBox(_T("当前Excel的版本是2007。"));) S% t& Y' L8 z) L
    }
6 U6 e$ o/ P2 M6 m5 q1 X7 R    else6 X8 v' S0 ]+ P. S/ o. T
    {
5 }; K+ I, t! o& _/ i5 t% u2 l        AfxMessageBox(_T("当前Excel的版本是其他版本。"));
  w$ h3 [- \/ @7 t5 k2 A6 e: {$ e: ]    }4 |7 C+ W  z- F

# @# \' V8 ?* G4 ^8 t    ExcelApp.put_Visible(TRUE);; W, p( r3 ~% d  Y' k# V
    ExcelApp.put_UserControl(FALSE);7 L! d# ?! t* Y5 }: q2 f5 P' j

2 D. a1 P+ _9 w% T1 a    /*得到工作簿容器*/- Z$ G! [3 Q9 k* n# e
    books.AttachDispatch(ExcelApp.get_Workbooks());
' E# v( L1 I2 p, Q, F
8 p6 ?2 J: ]8 @1 a- q    /*打开一个工作簿,如不存在,则新增一个工作簿*/8 P+ m3 T* V3 X; x3 V5 O
    CString strBookPath = _T("C:\\tmp.xls");, |( \# _* i- y# g: |1 @. f8 P
    try
+ u/ U6 A& \) a  z& c/ A    {2 ~, d: h) u4 x) r3 E. t
        /*打开一个工作簿*/  c' A8 _/ A; A- G% t6 s
        lpDisp = books.Open(strBookPath, , H* H1 K! H8 e4 W
            vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,! C/ `4 g. g  {* A) Q+ n* S
            vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,
* S" Q4 t& b9 o" I3 ~% R5 l# t) t            vtMissing, vtMissing, vtMissing, vtMissing);
( }( t9 ]6 p$ o        book.AttachDispatch(lpDisp);
# m) {% J9 a1 _* M6 Q# K3 b    }
0 v6 d! n( Q8 \8 A    catch(...)9 x/ t, ~! p- |) A9 U2 F
    {
6 ?/ ~) K& o& A0 a2 i        /*增加一个新的工作簿*/
; Z" ]$ a  v# W% W3 K0 D        lpDisp = books.Add(vtMissing);
9 n: C+ e0 t; e6 H" m        book.AttachDispatch(lpDisp);
* L! {$ u7 {+ U' g    }
1 x& V; F  K( L   
0 O5 h  ~3 p5 E: J, U
$ N" k$ }2 r2 W' \    /*得到工作簿中的Sheet的容器*/; f) X; b" ], n+ D4 b- {
    sheets.AttachDispatch(book.get_Sheets());/ z) @1 H; r# @" X- E9 D0 T. B) a
% U$ H$ g: |3 w
    /*打开一个Sheet,如不存在,就新增一个Sheet*/
# [. M5 ~: N2 U4 @    CString strSheetName = _T("NewSheet");; X$ G) L- k% U) l& j' D! f( s
    try
3 d2 c" W, W; K4 r. i# l    {. L; [4 z8 U0 C% O! ]
        /*打开一个已有的Sheet*/
: I! W- Q( A; i# p/ B        lpDisp = sheets.get_Item(_variant_t(strSheetName));8 R2 j8 j$ F+ w/ v
        sheet.AttachDispatch(lpDisp);
; W7 K/ c# s, [" u3 ^    }
. X% H2 L% r1 W    catch(...)  }) w4 f1 M$ M2 {* Z/ r( S
    {1 W+ N- k0 H1 L$ P! Q
        /*创建一个新的Sheet*/9 U- b: W: g' f/ B+ m9 `8 I
        lpDisp = sheets.Add(vtMissing, vtMissing, _variant_t((long)1), vtMissing);
) I- S+ Z% Y) P' x' r9 [        sheet.AttachDispatch(lpDisp);: q5 D0 M- S. B6 X9 {
        sheet.put_Name(strSheetName);
) B2 l  O" o+ V4 u6 w6 k; R    }
$ A( r3 r5 ~/ u  E2 l4 A
$ z( P2 P& ?5 f    system("pause");
! r5 v. c3 \! O6 c5 S; N) F% P  C
    /*向Sheet中写入多个单元格,规模为10*10 */) @! o3 \! y# v3 ~# R6 {, W3 f0 n
    lpDisp = sheet.get_Range(_variant_t("A1"), _variant_t("J10"));
+ G6 i6 o" R- ]+ ]3 u9 c$ w    range.AttachDispatch(lpDisp);
* V% i  Z# k1 q* _+ `& H) |/ F* q1 G+ g3 D
    VARTYPE vt = VT_I4; /*数组元素的类型,long*/* x1 F  d, u. O% p1 g0 f  [
    SAFEARRAYBOUND sabWrite[2]; /*用于定义数组的维数和下标的起始值*/; U" o: D: L- U; P) b$ f5 J: j
    sabWrite[0].cElements = 10;6 O2 d* v* s2 Z, A+ r
    sabWrite[0].lLbound = 0;
% i- V9 x7 W1 J/ v7 q9 Y& |    sabWrite[1].cElements = 10;% h2 o/ a8 W# q3 Q/ c/ H! B
    sabWrite[1].lLbound = 0;
: A+ d" m$ m" J7 h
4 k) p& _6 ?$ t& a    COleSafeArray olesaWrite;6 A8 i& `( o, s7 @8 b
    olesaWrite.Create(vt, sizeof(sabWrite)/sizeof(SAFEARRAYBOUND), sabWrite);
: ?/ E( o+ \- r8 S/ [$ c% D" g7 u' n9 T1 n
    /*通过指向数组的指针来对二维数组的元素进行间接赋值*/
) `- z8 \' J- v' N! u: e9 y  s: f! W    long (*pArray)[2] = NULL;
( ]( v/ K& N4 ^7 x0 h    olesaWrite.AccessData((void **)&pArray);
% c' \: u2 ]6 B7 N5 u4 k7 C# J( [  d$ Y. p    memset(pArray, 0, sabWrite[0].cElements * sabWrite[1].cElements * sizeof(long));( K* W! _& X0 {: k) D' a

; I; v. P  G* ?    /*释放指向数组的指针*/  C/ C( h+ R9 K( [6 L& C+ l6 v8 Y: m
    olesaWrite.UnaccessData();7 y1 Q3 V; C+ c
    pArray = NULL;
6 t- I3 `+ X0 K* l2 X
3 Q4 G$ j2 S# P6 d" w7 i    /*对二维数组的元素进行逐个赋值*/
0 D: d) N4 C( w. E- {' l0 `2 D0 R    long index[2] = {0, 0};$ f& G( Z8 y/ n( e
    long lFirstLBound = 0;
, u7 ?1 X' z; M! W3 ?( |    long lFirstUBound = 0;5 A4 b5 y' s9 d
    long lSecondLBound = 0;
7 U5 O8 o) @( B8 t. b( e2 s  I- j    long lSecondUBound = 0;
/ ]' Z" d. E( {    olesaWrite.GetLBound(1, &lFirstLBound);0 a6 F) M1 z( h
    olesaWrite.GetUBound(1, &lFirstUBound);
$ K8 ~  {8 z4 Q. ]) R* J    olesaWrite.GetLBound(2, &lSecondLBound);
* [) @4 b( ?* V) B    olesaWrite.GetUBound(2, &lSecondUBound);# s! p* |7 A; ~( Z, ^; x$ I
    for (long i = lFirstLBound; i <= lFirstUBound; i++)
3 t; T# ^# e( z' r# Q0 T3 A; V    {% Q3 s3 l8 }" h6 i$ v
        index[0] = i;: f' P! e* T0 d, B6 ?' t- U
        for (long j = lSecondLBound; j <= lSecondUBound; j++)) V" G1 m& H9 t7 v
        {. y* v2 E, }9 W, R" F6 `& N( C
            index[1] = j;
$ c' `9 z- O" [; M/ z            long lElement = i * sabWrite[1].cElements + j;
+ }' d# S) c5 }0 M9 P+ e4 Y            olesaWrite.PutElement(index, &lElement);9 O! l& A+ j0 i1 ]5 L
        }
+ X, J' d4 i+ b4 ~    }2 I, u1 g5 j  v7 `

3 }. O8 o! n; f3 K/ `    /*把ColesaWritefeArray变量转换为VARIANT,并写入到Excel表格中*/
6 ^) I; p9 ^  z3 Y) ^    VARIANT varWrite = (VARIANT)olesaWrite;
- h, `, R$ R; O! I# `9 T& Y    range.put_Value2(varWrite);4 W5 w$ Z; @+ n7 V/ d* c* G
  a, ]+ v' k+ P7 t3 P0 K- \
    system("pause");
2 }/ D) @( i. w4 h) l- V1 I
) R5 c/ \( ^* [3 A) O    /*根据文件的后缀名选择保存文件的格式*/
8 b+ e- q( k" H- K- m" M     CString strSaveAsName = _T("C:\\new.xlsx");. t5 s& P- l( d  c2 G, X! i
    CString strSuffix = strSaveAsName.Mid(strSaveAsName.ReverseFind(_T('.')));/ A; }% P! F( p6 k# Q/ _
    XlFileFormat NewFileFormat = xlOpeNXMLWorkbook;
% f( @4 O$ ?# k& F. f    if (0 == strSuffix.CompareNoCase(_T(".xls")))- @3 y' V! x+ n. m/ X+ E& z$ p; @3 W
    {
. k3 q. }) ~" Q5 Q& e7 i$ @8 i8 |        NewFileFormat = xlExcel8;1 t+ {( d' |/ x! u3 Z2 j% L8 e
    }* M* a, H0 y7 }: A8 x
    book.SaveAs(_variant_t(strSaveAsName), _variant_t((long)NewFileFormat), vtMissing, vtMissing, vtMissing, ! i  Q3 M, o; ]0 H( L/ o9 _
        vtMissing, 0, vtMissing, vtMissing, vtMissing,
: }% O; E/ d4 N' P2 I% N2 J* u        vtMissing, vtMissing);  H$ a4 e! j- F! k: }0 P
8 `6 D% A, [6 G. j7 N/ Y, x
    system("pause");9 h+ A+ F6 u  f. u: f8 K
' n' Y3 P6 I% r: y- |8 n; u6 j4 v! A
    /*读取Excel表中的多个单元格的值,在listctrl中显示*/
# z/ r1 j% [1 \/ |+ [5 [* T9 [    VARIANT varRead = range.get_Value2();
. l% r  u9 a) L2 a$ k3 H    COleSafeArray olesaRead(varRead);
% W% j$ V3 f+ g* A- y4 S
( S! o  K7 J( b    VARIANT varItem;
! `8 ^( ~5 A! C  t    CString strItem;" d* V' d3 M% \2 _4 }3 b
    lFirstLBound = 0;: Z8 T& R6 L$ Q0 c# L* B
    lFirstUBound = 0;6 s8 s% n0 c7 O: Z1 n* T9 j
    lSecondLBound = 0;
% T1 q3 M9 ~/ M5 P    lSecondUBound = 0;6 T8 c# S6 f) R# _8 R3 q1 a" \
    olesaRead.GetLBound(1, &lFirstLBound);
: S0 F! t% ~8 O2 H    olesaRead.GetUBound(1, &lFirstUBound);  M0 H8 F3 f9 W
    olesaRead.GetLBound(2, &lSecondLBound);
+ _0 p, d8 ~/ w    olesaRead.GetUBound(2, &lSecondUBound);* r% e( J( G6 p( W( A, [+ x
    memset(index, 0, 2 * sizeof(long));
/ u' h- T( Y. e& g$ v- s% D& @    m_ListCtrl.InsertColumn(0, _T(""), 0, 100);
' B7 L0 k& a, @: R7 f" W( [6 d    for (long j = lSecondLBound; j<= lSecondUBound; j++)) R( Q5 r2 a  h) O3 i0 P: R5 C
    {- u7 Q9 E) V7 G  A, A) r
        CString strColName = _T("");1 s6 {9 V6 @+ X/ R; m& n' ~6 f2 M
        strColName.Format(_T("%d"), j);& s; Y4 J' o2 x& o5 H
        m_ListCtrl.InsertColumn(j, strColName, 0, 100);
4 |4 j2 i$ F& a! e5 E7 p    }5 r: {' U4 J' T- |; G+ {% Y
    for (long i = lFirstLBound; i <= lFirstUBound; i++)
& j# s2 b" }1 D    {
# w; L5 [1 V, j) c/ b2 c+ P        CString strRowName = _T("");
- D" j2 W5 m! x        strRowName.Format(_T("%d"), i);: t: X% c: f( c
        m_ListCtrl.InsertItem(i-1, strRowName);/ p+ I3 \% P, j
: b) g* y- a0 i% x; a0 b; D4 J
        index[0] = i;
: H' W; Q* M! Y5 `3 {! d        for (long j = lSecondLBound; j <= lSecondUBound; j++)7 E) X! K3 r2 I: B" B5 i* B, ]( L
        {
$ a& q1 s, e7 O" d            index[1] = j;
# v% u6 \) s3 F9 m            olesaRead.GetElement(index, &varItem);
& M( b  q" s# a% J5 h3 R+ e# b- \, s
' Z2 p" U$ k& C4 C! S  ~& g3 ?8 s            switch (varItem.vt)
5 a/ b0 E# v6 W3 H- R) h( g5 N0 H            {
, a1 ~' _+ @. X2 i+ W            case VT_R8:
3 T9 Q0 B# i1 C- Q                {
$ l) n/ p: i! G$ R! J' S' |                    strItem.Format(_T("%d"), (int)varItem.dblVal);
! B. L0 D0 I: R$ i6 x                }
! x) r; n7 c% N. z/ R
; c6 I& |1 |+ x9 E3 a            case VT_BSTR:
- C% n5 k& v! x. m6 P- B                {! M& f, r3 y. W, z7 }. y
                    strItem = varItem.bstrVal;
$ b3 Q5 ~* O) r# j& W                }) A, V& B0 T/ v' D
2 ?+ i6 u8 d7 Y* i6 ~
            case VT_I4:
7 q" ~$ |: m6 p' N& N                {
9 j( N* _$ ~. i) ]6 a& m                    strItem.Format(_T("%ld"), (int)varItem.lVal);
; \, d" E% V$ V; B8 L                }
! T8 F3 r( ~; N, U9 k  L( E+ I2 i( v5 e, b0 }: O5 Y1 S: p& h4 w
            default:, o1 J9 ^/ l8 W" B6 ?
                {
! [6 [1 N, a% o( `' A# }  c" ]: G8 b7 s# P, F
                }
# \1 D( k# d' a            }0 t0 e  _' F% W4 n) v. {+ O/ z

  M9 E# n% r% j( f$ x  ~            m_ListCtrl.SetItemText(i-1, j, strItem);
9 y/ h2 C& k$ d& \        }
5 L/ `  {" V* X3 ?    }# ~& y2 A$ y8 T. Q, S
/ f- {8 N5 }6 C$ A

% Y+ v# {# I8 B8 m/ s- Z
( ^4 ~( W2 t3 T# G, `( \6 Z! k    /*释放资源*/
/ l* {# D4 x+ N8 ]8 T( z    sheet.ReleaseDispatch();
  T" p. q2 R" @7 k8 ?2 ^    sheets.ReleaseDispatch();' g) u& t: N" Z
    book.ReleaseDispatch();
) F- C  ?! {& I) v0 m% j    books.ReleaseDispatch();# W3 d# `' j$ T  A0 v# i5 V- h
    ExcelApp.Quit();
( u8 u3 R# s2 E# @- ?( \$ V    ExcelApp.ReleaseDispatch();[url=]
5 v- u7 P' k* i; m- y
                               
登录/注册后可看大图
[/url]

7 n6 i7 K$ `& c" b$ X6 x& u

3 B  i# _4 l9 b, J8 x/ d* K
上海点团信息科技有限公司,承接UG NX,CATIA,CREO,Solidworks 等CAx软件,Teamcenter,3D Experience等PLM软件,工业4.0数字化软件的实施\二次开发\培训相关业务,详情QQ 939801026 Tel 18301858168 网址 doTeam.tech
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 注册

返回列表 本版积分规则

  • 发布新帖

  • 在线客服

  • 微信

  • 客户端

  • 返回顶部

  • x
    温馨提示

    本网站(plmhome.com)为PLM之家工业软件学习官网站

    展示的视频材料全部免费,需要高清和特殊技术支持请联系 QQ: 939801026

    PLM之家NX CAM二次开发专题模块培训报名开始啦

    我知道了