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

[转载电子书] VS C++操作Excel详细教程

[复制链接]

2014-11-8 08:13:41 6807 0

2470

主题

1275

回帖

8万

积分

管理员

PLM之家站长

积分
82168
QQ
发表于 2014-11-8 08:13:41 | 显示全部楼层 |阅读模式

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

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

x
通过VC实现对Excel表格的操作的方法有多种,如:通过ODBC数据库实现,通过解析Excel表格文件,通过OLE/COM的实现。本文主要研究通过OLE/COM实现对Excel表格的操作。
, Q" U. Z( A' }; ?5 j' ?8 B: L  8 ?9 P2 J2 k1 s" D$ Y9 T* V
本文源码的应用环境说明:$ v2 u6 T( c8 u$ k( {5 j
Windows XP SP3) ]9 W' H1 F' J( R, c/ e
Microsoft Visual Studio 2010
" Z' z, n5 j4 @% |1 d3 DMicrosoft Office Excel 2007. U, U* j: R/ |4 k5 G& O0 j: J0 ^& _
  
5 i8 d9 S8 e& i1 u4 X" _1、添加OLE/COM支持。
/ F$ T5 h" x( @2 f/ q3 {$ i首先,应用程序必须添加对OLE/COM的支持,才能导入OLE/COM组件。
7 \# N1 o+ z) r5 n本文使用的是MFC对话框程序,在创建工程的向导中选中Automation选项即可为程序自动添加相应的头文件和OLE库初始化代码。$ W; E- y8 h. Y
通过查看源代码,可以知道在stdafx.h的头文件中,添加了OLE/COM很多类所需添加的头文件。5 H8 Q; W0 _3 E
#include <afxdisp.h>        // MFC 自动化类- c8 A5 R2 y2 R+ m% @4 }
同时,在应用程序类的InitInstance函数中,添加了OLE/COM的初始化代码,如下所示:
2 ]- X+ f; r* g& Q/ m5 @2 @( `// 初始化 OLE 库
6 S9 ~) H$ g2 }- p! Q; ^if (!AfxOleInit())
2 b( S  @, p: o" x{# |6 i  Q4 f9 c0 n7 k5 w- U
AfxMessageBox(IDP_OLE_INIT_FAILED);( f! \. |& ?  U6 O* |* `
return FALSE;
/ F" A! `' J/ J" c8 g3 s}
$ O* X6 a) ^+ u+ Y# H( w  " S8 E1 \1 J1 p5 X. m* k0 b8 `
2、导入并封装Excel中的接口  @* R8 C. X7 L( E
Excel作为OLE/COM库插件,定义好了各类交互的接口,这些接口是跨语言的接口。VC可以通过导入这些接口,并通过接口来对Excel的操作。
! x4 J+ U) z- Y# _由于本文只关心对Excel表格中的数据的读取,主要关注几个_Application、Workbooks、_Workbook、Worksheets、_Worksheet、Range等几个接口。Excel的各类接口的属性、方法可以通过MSDN的Office Development进行查询。( P9 u- J3 }$ T" d
VS2010导入OLE/COM组件的接口的步骤为:Project->Class Wizard->Add Class->MFC Class From TypeLib,先选择要导入的组件所在的路径,即Excel.exe所在的路径,然后再选择1 V! l0 I7 |3 R" N; J7 m8 Y
要导入的Excel类型库中的接口。
1 B1 r9 m' x( W, M在完成接口导入后,VS2010将自动为导入的接口创建相应的实现类,用于对接口属性和方法的实现。由于标准的C++没有属性访问器,只能添加一个两个存取函数来实现对属性的访问,通过在属性名称前加上get_和put_前缀分别实现对属性的读写操作。即,由VC自动完成C++类对接口的封装。% s$ U6 G5 H4 Y$ D4 S+ L
  : F: V* t4 f* I
本文所导入的接口对应的类和头文件的说明如下所示:
( ?& \/ V1 \0 f- `3 c7 K  
  T( _1 d0 |$ iExcel接口7 ^8 a" I7 k7 A/ b2 a0 l. y
导入类
& O9 @" m! t- d- d1 }头文件
' D. g; w  W0 A) Q' R& i% A说明2 W0 u) H7 s: S) M7 G* D/ V
_Application
8 n$ u$ q& Y! K' E6 y8 h1 a7 ^CApplicaton# m3 S& b2 u  o- F# p2 U# t
Application.h
) A' t% p% h9 x; ?% MExcel应用程序。
% D6 d' [+ H% I5 B  j" X0 iWorkbooks
$ ^& _4 ]4 o# c4 WCWorkbooks
2 ~4 U1 D: J; |( \4 p- L/ C' Y7 sWorkbooks.h
( W+ E4 v7 Z% @9 r2 B- n2 C, R工作簿的容器,里面包括了Excel应用程序打开的所有工作簿。
' w7 L( x* R5 J1 ]) ~2 H" x_Workbook! `% p7 K7 T, a6 t# f
CWorkbook" D9 q8 S+ I( a- p% s5 @8 D' ~
Workbook.h
4 T0 C7 S$ A& y; y; A单个工作簿。
& A2 x) E$ F9 ?/ C' Y: v7 UWorksheets4 P4 p( S1 _, l  i6 |0 ~
CWorksheets2 g1 x% |9 {1 l, m
Worksheets.h
# V/ N/ r+ Z, }* ^& z& V; b$ o! ~单个工作簿中的Sheet表格的容器,包括该工作簿中的所有Sheet。
' q4 M" D" g3 c, __Worksheet
$ L% B- W+ Z: f7 p; c& qCWorksheet
5 G2 K7 R6 S; m- o2 eWorksheet.h8 s9 @, G& Z  [8 d$ o' N- R
单个Sheet表格。
% H2 \) R  m3 g! R) h8 F* }2 K, DRange# y* d( V+ w8 W  W2 n0 Z
CRange
. T: N) Z7 K- f/ o: A3 QRange.h& e. U) z" }% @  U
一定数量的单元格,可对单元格进行单个或多个单元格进行操作。$ ~7 U+ Q3 o5 Y2 w
  
" z0 y( j3 T/ z  D3、导入Excel的整个类型库: L7 p1 s  w5 b! s7 g8 k% }& B
接口对应类只是对接口的属性和方法进行了封装,而Excel中的数据类型,如枚举类型却并为并不能使用,因此,为了更方便的操作Excel,还需要导入Excel的数据类型。
3 [2 H2 R+ O1 j5 s; Y/ G通过查看导入接口对应的头文件可以发现,在所有导入接口的头文件中,都会有这么行:
! U1 b( e5 ]( D7 S  Z9 \7 l+ @#import "D:\\Program Files\\Microsoft Office\\Office12\\EXCEL.EXE" no_namespace1 f: f5 p, l$ W: p/ M* X
这行代码的作用是导入Excel整个类型库到工程中。
. R( y' f+ A" J由VS2010自动产生的导入代码存在以下几个问题:' F0 i. j. t/ K5 l) E& [, W7 [( K
(1)如果导入了多个接口,每个头文件都会把类型库导入一次,如果引用多个头文件,会导致类型库重复导入。
; d9 q. z1 W: ?, t* O- q# `(2)Excel类型库中有些类型会跟MFC类库的某些类型冲突。
# \# z, O5 X, i+ a9 D(3)Excel类型库的某些类型跟其他Office和VB的某些库相关,如果不导入相关库,将导致这些类型无法使用。。9 _2 s: d1 B) Y4 e
以上三点问题的解决方法如下:+ O) j8 i; h4 }: j9 n- L
(1)仅在_Application接口对应头文件中导入Excel类型库。% v7 w8 r: I$ d0 D
(2)对冲突的类型进行重命名。  R9 J! n1 Y2 f3 {8 M+ u& A8 b
(3)在导入Excel类型库之前,先导入Office和VB的相关库。
. d, J" Z% V) u% v) h* r/ l更改后的导入类型库的代码如下:
* C: r; ^5 r5 [3 J  
& H+ m2 l- ]% p$ j2 H9 u1 \/*导入Office的类型库*/
3 h& q' d/ ^0 F8 b+ X5 B7 x$ E#import "C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE12\\MSO.DLL" \
2 M2 ?6 M1 B+ E  q5 L! p+ h4 t# krename("RGB", "MSORGB") \
; V4 G! {) H. h6 y* }# I  I, Hrename("DocumentProperties", "MSODocumentProperties")
* B) m* o! |/ M0 Z, ?( Cusing namespace Office;4 B2 m- W' e5 m. x' k
  ' z- i' X5 o, x! g$ A
/*导入VB的类型库*/& j6 p9 [$ `8 `" V. O: P$ x
#import "C:\\Program Files\\Common Files\\Microsoft Shared\\VBA\\VBA6\\VBE6EXT.OLB", z5 I; r& l) R; V6 N  l8 C$ G
using namespace VBIDE;
! X0 T! Z0 x5 ?  B+ W  . D2 J/ |) _) K% `# n' {  f
/*导入Excel的类型库*/7 }3 z1 F) c, }# l8 c) w
#import "D:\\Program Files\\Microsoft Office\\Office12\\EXCEL.EXE" \
) f! d  x$ p/ }( H: U0 X' brename("DialogBox", "ExcelDialogBox") \: k# c  \3 ^  R$ n) O; ~9 e
rename("RGB", "ExcelRGB") \
2 m$ B* |% X$ T! i9 V( Y! krename("CopyFile", "ExcelCopyFile") \4 U* C3 u$ y  N' t
rename("ReplaceText", "ExcelReplaceText") \! Y2 P2 i/ l7 P% Z  _
no_auto_exclude
- C7 W+ s/ o* v; LUsing namespace Excel;" C! H* {+ G/ X$ t/ A
  
- b' R+ u- @# s' Q7 W9 M0 Y编译程序后,会在DebUG或Release目录下生成三个文件mso.tlh、vbe6ext.tlh和excel.tlh。通过打开文件可知,该三个文件的命名空间分别是Office、VBIDE和Excel。导入了Excel的整个类型库后,就可以使用Excel中的所有类型了。
, Y  b9 ~+ N3 u, K! ]  2 b$ X" q2 L1 ?0 W$ s" C
4、操作Excel步骤$ t5 N! a, v" I& U% c/ n# a% v
操作Excel的主要步骤如下:
" \' l* n/ T1 r2 x7 {: S(1)创建一个Excel应用程序。0 R. ^" }6 t+ J* g
(2)得到Workbook的容器。
# s  |  q+ v4 |( C2 p9 S(3)打开一个Workbook或者创建一个Workbook。' L( x2 L2 m4 @# o6 k
(4)得到Workbook中的Worksheet的容器。
3 X* B$ w# b8 s- g0 {(5)打开一个Worksheet或者创建一个WorkSheet。: h; {$ {& q& T
(6)通过Range对WorkSheet中的单元格进行读写操作。
* g$ L7 U4 t4 T; z' @(7)保存Excel。
* p  y5 a2 S* Z% K(8)释放资源。
3 y  e$ r$ t0 X  
8 R5 q& w, T$ _6 j& T5、批量处理Excel表格
- W6 O0 K& X8 a& XVC通过OLE/COM操作Excel,是通过进程间的组件技术。因此,每次读写Excel中的单元格时,都要进行进程间的切换。当数据量大,如果一个单元格一个单元格的读取,主要的时间都花费在进程切换中。因此读取多个单元格,将可有效的提高程序的运行效率。- m1 I% d: b  x( ~; v: P2 d
对多个单元格的读写操作可以通过CRange中以下两个成员函数来完成。) _; h* M' P3 e- Y- M  ?0 f
VARIANT get_Value2();
' B# b! C& I  ~$ y1 G7 E8 [& Nvoid put_Value2(VARIANT& newValue);
0 U! s' o9 o* H$ o9 ]+ P8 g# y4 d6 f其中,输入参数newValue只要输入一个二维数组,即可实现向Excel中一次写入多个单元格的值。
8 @7 d6 j! H* G; Y* n其中,VARIANT中实现二维数据的方法可参考5 Y  R$ a% A# B% ^4 Y: [
http://www.cnblogs.com/xianyunhe/archive/2011/09/13/2174703.html5 _6 }( T' \  }' j+ f
当然,在对CRange类进行操作之前,要设置CRange类对应的单元格。
  k9 J$ h, |+ n8 f* s  
5 D" Y! c: w$ M) s2 V' i6、Excel表格的保存
4 ?/ I6 q  i- q; X* y  ]( V  q' y(1)如果要保存打开的工作簿,使用CWorkbook类的Save函数就可以保存工作簿,原文件将被覆盖。/ Y$ \) n# L% f! _% Q0 r; G3 p
(2)如果是新创建的工作簿,或者是要另存为,可使用CWorkbook类的SaveAs函数。. `9 i  S$ q! n7 A& R8 }
SaveAs的参数比较多。其中,第1个参数是设置要保存文件的路径;第2个参数是设置文件的格式,可在MSDN中查看枚举类型XlFileFormat来了解Excel的文件格式。经过测试,在本文所用的测试环境中,Excel2003的文件格式是xlExcel8,Excel2007的文件格式是xlExcel4。- _8 a" Z% n6 m6 |( q
  % e0 b% X; j. I" s
7、获取当前Excel的版本
" d/ a2 S5 T1 A可以通过CApplication的get_Version函数来获得Excel的版本,其中,Excel2007的主版本号是12,Excel2003的主版本号是11。
/ k( `9 l# a  W; ]# M2 z1 y  [% o  ( W6 i' ^7 k3 c: |* u
8、示例源代码
3 x$ e5 O% ?& w$ @3 t( ?! A主要代码如下:
( J* y! P+ H/ n# K, g  8 H) w2 C5 e) Q4 q7 l: g8 l6 C

) R7 M/ l0 r+ n9 H! F+ G9 R  _5 }2 O. t/ h8 R
    m_LisTCtrl.SetExtendedStyle(LVS_REPORT | LVS_EX_FULLROWSELECT);0 c4 X" |. K( H7 H$ x

* T3 n* V) j. _) e8 @8 {' W3 O    CApplication ExcelApp;
0 x& Y: ]# H/ a5 d    CWorkbooks books;$ r  J3 n7 l1 t  Z( ?$ }
    CWorkbook book;
! `0 J* K$ k% w* }    CWorksheets sheets;
! k" M- A+ S" r$ d$ A    CWorksheet sheet;
: }$ q) X/ ?9 A8 _- b2 C  ^$ {    CRange range;% w& X6 ?* K) _* ~! g- G
    LPDISPATCH lpDisp = NULL;: V7 ?+ a! O) A& N! }5 u
" x. l- Q* o) A1 R
    //创建Excel 服务器(启动Excel): U+ J' {. d& I" ^: s
    if(!ExcelApp.CreateDispatch(_T("Excel.Application"),NULL))# f3 b  v; C# n
    {
5 _  b3 u0 j- c! x1 V        AfxMessageBox(_T("启动Excel服务器失败!"));0 L3 |0 s3 F& c4 C6 _0 Q0 F3 L
        return -1;; ?$ w/ @- ^% p2 h6 H; L1 Z1 _- p  f
    }# H: x% W0 e9 Z) j

1 X* C$ m2 s& e+ l* D    /*判断当前Excel的版本*/! L4 U; h$ n" f
    CString strExcelVersion = ExcelApp.get_Version();' A; A3 t! b# h, \
    int iStart = 0;
8 b; h% _8 h' `4 k% a0 _    strExcelVersion = strExcelVersion.Tokenize(_T("."), iStart);5 N  e( ]+ ]# h: ~
    if (_T("11") == strExcelVersion)
( w0 }7 J4 S# L5 X# A  w9 ?    {1 c: z+ C6 m  k7 O& v6 \3 d
        AfxMessageBox(_T("当前Excel的版本是2003。"));
! V8 z% m( \. X, E" Z8 P0 Y; t" X    }
% a. j# C/ ]# L: p: a5 c    else if (_T("12") == strExcelVersion)9 o. g4 f4 `  I; W  _$ W  U8 J
    {/ {) e# O2 y4 }9 {0 R$ z4 W6 J" q
        AfxMessageBox(_T("当前Excel的版本是2007。"));5 R/ {, Z) T% @' J0 b, V; g
    }( G) @! f* ]2 o8 T
    else6 m1 J! c% `6 p
    {9 a2 K6 V" d( n) m! a7 x5 n
        AfxMessageBox(_T("当前Excel的版本是其他版本。"));
: P+ G7 J/ J5 M    }
0 g2 v  Y0 V. _, L% n& J, n. Z3 K" z
5 n0 @1 m$ j6 `& O    ExcelApp.put_Visible(TRUE);
: K" a. t# l' ~" }1 k8 j6 S    ExcelApp.put_UserControl(FALSE);9 q0 {0 R3 Y" R

+ h. W- c& p) T% a$ E+ P, L    /*得到工作簿容器*/
% h; y( i# x: w5 w$ D. b    books.AttachDispatch(ExcelApp.get_Workbooks());
6 X, H2 D! T  ]4 q' O0 U: a
! ^3 `5 {1 _$ _# j9 [: W; j+ y    /*打开一个工作簿,如不存在,则新增一个工作簿*/, y* y8 v  ^; W+ T
    CString strBookPath = _T("C:\\tmp.xls");
+ G% m8 G2 t3 V    try9 {( g! I" e# V- E
    {8 S  d2 h0 F- e3 t7 z" C- T' `
        /*打开一个工作簿*/8 }- ~/ W5 b2 |, o4 Y' D( \
        lpDisp = books.Open(strBookPath,   [1 F* }( ]$ S* j$ T; ]
            vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,
* e4 p* d5 V! z3 p. j            vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,
! `& _$ d. L1 b            vtMissing, vtMissing, vtMissing, vtMissing);
; p8 P4 u* a- K( g: U        book.AttachDispatch(lpDisp);
& x/ j% s5 Y/ w    }
) a6 \. t) J- y8 Q' }: S' g    catch(...)
/ u( ^0 A0 c/ H' H9 E+ d! @4 G: q5 R    {5 }' y. h+ U  @+ I- {; I
        /*增加一个新的工作簿*/  R, w9 U* b% [9 Z3 }4 B
        lpDisp = books.Add(vtMissing);4 G, M( n: J9 U
        book.AttachDispatch(lpDisp);4 C, _/ F2 F9 h3 [2 d4 Z& ^9 S
    }
; G# a1 J  z& d1 f     / i- q! T4 `0 N
& p& x! [0 `9 }: W
    /*得到工作簿中的Sheet的容器*/  J' E& E: L) ^/ A0 F
    sheets.AttachDispatch(book.get_Sheets());
; d4 @5 }- o! K0 Q% h
7 v& a6 @9 O5 u5 ~$ s    /*打开一个Sheet,如不存在,就新增一个Sheet*/* s9 q/ l8 Q* x  V( h
    CString strSheetName = _T("NewSheet");
: K! G, r) ?- h4 s* R    try
2 Z+ B& j- y! e) }# M    {5 P1 I8 z4 p5 t0 l' Z( k
        /*打开一个已有的Sheet*/- \0 Z# R6 ?9 ^) s8 W7 |
        lpDisp = sheets.get_Item(_variant_t(strSheetName));2 h# T/ g4 [6 d3 \
        sheet.AttachDispatch(lpDisp);6 w7 t8 x' z0 y( p, |, [+ F
    }1 v4 |& B" Q% ]: K
    catch(...)
7 x: J5 C) ?( a    {
3 g) ^! [/ U% G) d5 H0 J6 b        /*创建一个新的Sheet*/  R0 ^: T1 D2 _3 x
        lpDisp = sheets.Add(vtMissing, vtMissing, _variant_t((long)1), vtMissing);
3 V( J5 H$ ~: j. Q        sheet.AttachDispatch(lpDisp);# ~( M8 C( P$ Q6 `; z* R
        sheet.put_Name(strSheetName);
) P. H! q0 Y) q9 A9 Q2 `    }
/ s) h' T2 Q. U: x% [! T
0 Z0 _9 Y, A, z3 c. B; k    system("pause");
5 K* }+ `7 R; Q6 s& _9 m& z% T  _" d& Q. o/ n. c( u) c9 E4 Z! P; c& d
    /*向Sheet中写入多个单元格,规模为10*10 */& d+ X; y: `. v' c5 H7 A
    lpDisp = sheet.get_Range(_variant_t("A1"), _variant_t("J10"));& C; n1 y9 K( f3 v4 Z
    range.AttachDispatch(lpDisp);) w  D* C0 J# C- U

2 L6 q5 h$ ]6 ]    VARTYPE vt = VT_I4; /*数组元素的类型,long*/" `5 g, o; \& `1 S6 \1 a5 a) z. {0 \
    SAFEARRAYBOUND sabWrite[2]; /*用于定义数组的维数和下标的起始值*/
% W% |: A' D: G3 ~    sabWrite[0].cElements = 10;
' S6 G( D: v) I# y8 x" y# ~    sabWrite[0].lLbound = 0;
3 P, Z- N* N& h    sabWrite[1].cElements = 10;- k& s( J) c; L: x8 Q, }
    sabWrite[1].lLbound = 0;
+ b( J( |1 N7 C# @- E6 @, x* Z5 q# r0 j1 ]/ t8 e5 h# Y  Q+ O
    COleSafeArray olesaWrite;$ \8 T% x+ n. T, W6 w1 J
    olesaWrite.Create(vt, sizeof(sabWrite)/sizeof(SAFEARRAYBOUND), sabWrite);2 S% {# F+ z9 C! L

- Z( v4 p% B. t3 t    /*通过指向数组的指针来对二维数组的元素进行间接赋值*/+ S6 [7 U' X0 y3 V( G
    long (*pArray)[2] = NULL;/ D! }! n6 J5 M7 k3 l0 r- }0 y% \. l
    olesaWrite.AccessData((void **)&pArray);
" m, }8 W  k! X7 |; S: @, j# |4 S    memset(pArray, 0, sabWrite[0].cElements * sabWrite[1].cElements * sizeof(long));
: w6 Z6 `; {, Y
: D7 D! c' j/ y. a/ O% s    /*释放指向数组的指针*/
5 i% y* v; e# J1 U    olesaWrite.UnaccessData();
3 @9 L: U* Q: V( x, y; X5 K    pArray = NULL;- w! q. g( D1 a% ^, W( ~3 N
7 R# u' ?4 I& P* X& T+ Q2 o
    /*对二维数组的元素进行逐个赋值*/- e, t& @" w- P. M
    long index[2] = {0, 0};  e; T5 Q, P" @1 P; v# S1 G
    long lFirstLBound = 0;2 x- y! p4 I. z( @# d" [
    long lFirstUBound = 0;$ E# H6 R+ L" e" }; `4 X* M3 r
    long lSecondLBound = 0;
3 H4 ]9 R3 J' U( h& u1 Y8 |' ^    long lSecondUBound = 0;
, x7 ^5 K  S1 M9 _# q, M    olesaWrite.GetLBound(1, &lFirstLBound);% F7 ]3 C! w1 B* h
    olesaWrite.GetUBound(1, &lFirstUBound);; T6 u6 P# f: ^4 J# [- x7 K! A
    olesaWrite.GetLBound(2, &lSecondLBound);
2 x: ]3 ]5 E, }2 o& L/ a    olesaWrite.GetUBound(2, &lSecondUBound);1 w: q* o9 X. q; ~9 }* g
    for (long i = lFirstLBound; i <= lFirstUBound; i++)
! K5 T0 i/ x, _- Q9 K    {4 P6 ]" B7 ]/ V
        index[0] = i;
$ Y3 f3 F+ q0 q        for (long j = lSecondLBound; j <= lSecondUBound; j++)
" k& Z- V& c7 z% _, {( M2 V+ \        {
5 H8 y# `( @% I/ ?) c- z; S( R; A            index[1] = j;/ h' u7 m! X: a) d" S- D
            long lElement = i * sabWrite[1].cElements + j; 6 q9 \% a+ }! e
            olesaWrite.PutElement(index, &lElement);2 ]0 q8 ~1 [9 a9 p/ P
        }
4 i" D. G/ @* `% W. ~5 l1 ^    }
5 x, Z! N4 G- Y
/ Z5 z+ Y2 H* l) \4 x    /*把ColesaWritefeArray变量转换为VARIANT,并写入到Excel表格中*/. Z8 y8 I, A) f) }
    VARIANT varWrite = (VARIANT)olesaWrite;- e" [- }# t! t. Z6 k' i+ a
    range.put_Value2(varWrite);, |' p. U( ~5 A- o+ T) }" t8 t
0 h& G( g( k- H8 V4 X: q" J2 w
    system("pause");
( q. Q+ Y* ]4 D8 y2 V. h0 D" b
2 C- i' K  \, p$ _8 ~" i8 M1 z6 _    /*根据文件的后缀名选择保存文件的格式*/
6 g4 \- N  d: X. y     CString strSaveAsName = _T("C:\\new.xlsx");
) P+ s, d# H/ K; s    CString strSuffix = strSaveAsName.Mid(strSaveAsName.ReverseFind(_T('.')));* n4 V, A9 I  p/ p% E$ L
    XlFileFormat NewFileFormat = xlOpeNXMLWorkbook;( S( S% Y# v. ~8 A  P" E
    if (0 == strSuffix.CompareNoCase(_T(".xls")))
8 ?" p4 Z' _7 `1 Q; Q    {
' q( d# c. O+ [/ B/ W        NewFileFormat = xlExcel8;7 a# z" G- W8 J  d( ~3 C
    }
8 l- N9 F) s# h7 B    book.SaveAs(_variant_t(strSaveAsName), _variant_t((long)NewFileFormat), vtMissing, vtMissing, vtMissing,
. X9 a$ e( e: D7 z        vtMissing, 0, vtMissing, vtMissing, vtMissing, + R* y& _# |8 C1 F2 g  o
        vtMissing, vtMissing);/ g2 c4 v- l/ G" c  {4 s$ S# M

9 j8 x8 W! u$ e  \$ A6 c    system("pause");
" E/ F3 g& y: Y7 p* N  H8 J4 }8 d8 N5 B6 A& R* I0 O8 L) y/ u0 A
    /*读取Excel表中的多个单元格的值,在listctrl中显示*/  {' D- @& y8 q! h5 t2 M- o: X
    VARIANT varRead = range.get_Value2();
5 W. g8 O% @1 k: W( W    COleSafeArray olesaRead(varRead);9 u0 h+ o: ~2 E; Z) M* s
6 K7 F) [: C/ v2 w* C9 D: l
    VARIANT varItem;
5 `0 S4 J  q7 v# `7 Z& l    CString strItem;
. U! ~8 {; M  M  d  j. A3 x* {    lFirstLBound = 0;" R0 L2 ^% R) x* |: Q6 e
    lFirstUBound = 0;+ N3 Y' J7 z% @! ~) M. D
    lSecondLBound = 0;
# |/ }% M; c1 j4 ?# ^3 r* R' i    lSecondUBound = 0;
0 u9 P+ @% M4 i  F0 M! `$ y" ~& ]    olesaRead.GetLBound(1, &lFirstLBound);
, g4 C8 T$ z2 h- f+ F    olesaRead.GetUBound(1, &lFirstUBound);, c; k* Q& |) j
    olesaRead.GetLBound(2, &lSecondLBound);
  b$ R! v# W0 y% R    olesaRead.GetUBound(2, &lSecondUBound);
- c% r. H# R; C% l1 |& D' T% O    memset(index, 0, 2 * sizeof(long));
+ J8 }% z! m6 \" A0 A- p, n8 y    m_ListCtrl.InsertColumn(0, _T(""), 0, 100);
/ j3 m: [' B( f( X    for (long j = lSecondLBound; j<= lSecondUBound; j++)7 R2 U9 U7 u" ]& x! `0 q
    {# V. O$ p) Q! H
        CString strColName = _T("");3 c' M2 b/ ^3 Z9 U# F. I
        strColName.Format(_T("%d"), j);
( ^' C. r; e" e6 M1 Y. U! C' H, z        m_ListCtrl.InsertColumn(j, strColName, 0, 100);
; ~' w8 q% x7 ?7 y2 V    }; F3 c  U( c0 Y% S+ _& J0 _
    for (long i = lFirstLBound; i <= lFirstUBound; i++)
2 v# K& J. b# k' @( {    {( q+ h0 k4 u# E$ \
        CString strRowName = _T("");
& a6 A  k; p6 q6 W/ p. [) Q+ E' P        strRowName.Format(_T("%d"), i);
7 b# u2 H% F6 u4 g- o        m_ListCtrl.InsertItem(i-1, strRowName);
" x! d! G* z. U7 ?
! G+ k) C: \* K/ Y  |        index[0] = i;6 Y' [% j3 T  t8 |/ k5 Y! B0 p
        for (long j = lSecondLBound; j <= lSecondUBound; j++)* O& q: _. ]6 N) {0 l7 N2 f. E
        {. O, D5 u1 M5 {/ ]. s1 {
            index[1] = j;
3 ~! a; C5 Q' h$ {            olesaRead.GetElement(index, &varItem);1 ~3 T  _9 ]. F# Z" d3 c$ W+ c4 Z( q7 L! X

# J, U) t$ a# U' |6 C1 H$ t4 O            switch (varItem.vt); V2 B4 f; A7 o9 \$ y- ?0 m: R
            {
4 C5 A6 l. D* r            case VT_R8:
  G, R; P& }$ X! H6 u9 ~! M                {
5 R/ F! J" a3 H; L( W0 M$ J# D                    strItem.Format(_T("%d"), (int)varItem.dblVal);
- m( a2 }' B  L0 Y% t3 W                }, @9 H/ C; V. p+ d5 l% r- h% b
- l7 x! W1 N( G' {# ?
            case VT_BSTR:+ _  Y) ^+ y6 U
                {
3 `8 r/ k4 x, L8 k                    strItem = varItem.bstrVal;# t8 f& j6 B6 [3 F
                }; `7 i/ j8 w& f+ n( \# a
' b, u1 W# t! v  M+ J. T
            case VT_I4:  B8 ]! P" u: }: [( a* u
                {2 {! n8 u' w6 l- V
                    strItem.Format(_T("%ld"), (int)varItem.lVal);
/ t* j; T$ J& G( |( |+ o7 V) o                }- G5 @% E  n1 r: x8 A( A
! c) L" s2 r& d
            default:
) h4 G% H) ?9 ?! v                {$ _  j1 n+ C; c, t5 u* `8 j

% g. o$ n; v7 B1 i/ V6 g                }& c* |1 ^$ d) T0 c$ [3 ^
            }8 q! p: `) l+ w0 d1 T: A7 h. Z
; d6 A: L5 r8 T$ j, K% K
            m_ListCtrl.SetItemText(i-1, j, strItem);/ |8 M  h: _$ f
        }+ O* {; @# S3 F* Z' ]5 S
    }
/ j6 u# i2 f0 _; v; q5 r& m# B
, t/ T- @: x1 z1 A4 g
$ p! Z' T; e6 r2 k' x+ ]4 c; `' `& G* K; Q- G9 k4 i0 h! X& e' R
    /*释放资源*/3 U; c6 d! S/ X9 ^
    sheet.ReleaseDispatch();+ t/ i: R' h8 f, |8 p) p8 e
    sheets.ReleaseDispatch();) q& h2 i8 u6 G$ N
    book.ReleaseDispatch();7 `1 Y4 ]" c5 w3 Q: b* J7 ?9 t
    books.ReleaseDispatch();2 U) g7 |- N) o' Y
    ExcelApp.Quit();
8 l* s6 }0 j4 W    ExcelApp.ReleaseDispatch();# d) C5 A7 _4 b$ e( w, N

/ E: F% k+ o( q, v1 Q; }
上海点团信息科技有限公司,承接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二次开发专题模块培训报名开始啦

    我知道了