|
ug二次开发中外部数据访问方法研究 1 前言
) j1 C* V2 y, x随着UG系统的推广和普及应用,基于UG平台的二次开发工作显得越来越重要,在UG的二次开发应用系统中,经常需要与各种外部数据打交道,
( P2 W! l% V+ @4 n' S) V
8 r6 g* ^2 A$ ?& a8 }+ G, E( A( @UG/OPEN API提供了丰富的文件访问操作函数,利用这些操作函数及VC++的MFC类库,可以方便地实现外部数据读写访问编程。 % j, u& Z, F" [0 B0 Z3 v
2 外部数据访问的主要方法 ; M- O! S& }9 \
在UG二次开发应用系统中,主要访问的外部数据有文本文件、Excel表、关系型数据库表等,通常可以通过以下方法访问这些外部数据: # W6 o/ J4 F0 L! N! d( C
(1)通过UG/OPEN API提供的文件操作函数访问外部数据 3 C2 c. ^3 r. N: V6 {3 b7 ]+ r
(2)通过ODBC数据源访问外部数据 , b1 |1 [+ g5 ?- [8 H, R$ S+ v" O
(3)通过ADO访问外部数据
! ?, ]% I0 |; v! e: r Z2.1 通过UG/OPEN API提供的文件操作函数访问文本文件数据
, C3 c3 P1 o& C7 k0 f% IUG/OPEN API中有关文件操作的函数包含在头文件uf_cfi.h中,通过函数uc4500可以打开二进制文件,相关的文件操作函数有uc4510、uc4511+ s; y, j0 X, x; l* \0 k/ _
- I7 C! }6 D2 m4 |/ T
、uc4512、uc4513及uc4520、uc4521、uc4522、uc4523,通过函数uc4504可以打开文本文件,相关的文件操作函数有uc4514、uc4524、uc45254 M7 }9 b5 H0 s0 E3 m; ?) X' d% _- O
$ w' s9 K$ B I1 d7 W& o
,函数uc4540用于关闭文件,判断文件是否存在使用函数UF_CFI_ask_file_exist。 " D6 b$ _; F! h
通过UG/OPEN API提供的文件操作函数访问外部数据时,要注意以下问题:
9 G5 {: E6 I7 M(1)UG/Manager 和 IMAN中的文件和文件夹操作不能使用uf_cfi.h中函数; 3 C0 S5 R; w- L' T) |- N i
(2)UG/OPEN API中对文件和文件夹标识符的长度有如下限制:
& Q8 B+ h5 z: k& u2 I文件名长度不能超过UF_CFI_MAX_FILE_NAME_LEN;文件夹路径的长度不能超过UF_CFI_MAX_PATH_NAME_LEN;整个文件路径的长度不能超过
1 I( d$ K7 V( ~. ?- h6 B6 \$ `1 U1 Z* \8 u0 e# f6 A* {- u
UF_CFI_MAX_PATH_NAME_LEN。 / R- H! I$ N( D
访问文本文件的程序流程如下图: % L. E/ B5 W ]) F
# t p* Q5 K/ Q/ h' \- s. e2 l
2.2 通过ODBC数据源访问Excel表或关系型数据库表数据
# q/ W9 V! ]3 a# T! I: A$ j' hODBC(Open Database connectivity 开放式数据库互连)是由微软公司提出的一个用于访问数据库的统一界面标准,它提供了一个一致的应
& K4 K) M; ]$ C' t# i" n1 R
6 Z3 V8 F: ]# P% E4 I! H7 ]# E用程序编程接口,该接口使用一个针对数据库的驱动程序与不同的数据库协同工作。 0 C% E: h9 C1 F! B: D+ ?( `
通过ODBC访问外部数据时,需要先指定访问的数据源DSN(Data Source Name),以指定ODBC与相关的驱动程序相对应的入口。在控制面板的
' h: J$ S7 z* B* N2 ^
8 e! ~- {5 r% l管理工具中可以打开ODBC数据源管理器,指定DSN。
" G8 W. k3 J, W) W5 w建立MFC数据库类Cdatabse对象可以实现对外部数据的访问编程。一个CDatabase对象代表与数据源的一个连接。创建一个CDatabase对象之后
2 D, h* {- V+ o) H9 T& a' E# A
" q/ ?3 M/ l0 ]3 I% \- X,调用Open或OpenEx成员函数指定一个DSN,就建立起了与DSN的底层数据源的连接(打开数据库)。成员函数Close关闭数据库。CDatabase对: T: ]4 |0 _! ?4 f+ |" q2 B; ~! r
: l/ a% ~, O' J U/ _" z% j
象通常与一个或多个记录集(CRecordset对象)一起使用,通过CRecordset类的各成员函数完成对数据源的读写操作。
: w. ]. o. y+ i) p6 h+ i4 d7 w通过ODBC访问一个Excel表的编程实例代码如下:
# C0 Y/ G. E3 M2 ystatic void do_ugopen_api(void) . M m1 _2 j- q5 }3 }
{
! @3 I$ I A, d! ?CDatabase Database; // 定义一个MFC的CDatabse数据库类对象Databse
$ ?2 u: P! U* K% xCString SQLCommand = "select `Serial_Number`, `Outer_Diameter`, `Inner_Diameter`,`Height` from `Sheet1$`"; // SQL查询语句
$ X+ K# |% ~& m# @DWORD dwOptions = 0;// 设置连接的建立方式
- }9 G. G4 h+ v7 f* v: pCDBVariant temp;// 数据库数据通用类型
9 ^. `2 n% D$ N3 R6 ?int result; // 储存返回值的变量 6 q7 L* O/ p+ W7 Y
char buf[133];
3 t1 W# ~7 ~. b- I# Wtry `& W- F$ x) m; n' T4 f$ g
{
t' d, j7 I$ U7 C, \3 tresult = Database.OpenEx( "DSN=Standard Part", dwOptions ); // 打开数据库 $ S7 h( M* U7 n3 k5 r3 [
if( result != 0 ) // 如果成功打开
7 c$ @8 d3 P$ E& _0 b( P. i{
}$ s5 n# J9 aCRecordset rs( &Database ); // 定义记录集
: W( D: \4 x( I& u3 m+ vif ( rs.Open( CRecordset::snapshot, SQLCommand ) != false ) J b* {! y0 x# ~ f1 T
{
3 \ j* A' N& m* n6 d% E( Hrs.MoveFirst( );
, a( E( N5 [0 X! J: E/ d' E, s2 Xshort nFields = rs.GetODBCFieldCount( );// 获取记录的字段数目 5 }. V2 T9 C9 U, B: M
UF_UI_open_listing_window( ); & J4 V. K M5 M1 H( q* O; q
while( !rs.IsEOF( ) ) 0 }/ S7 E2 {/ A( X5 s+ Y
{ . p) G* d n# h5 T- B) z
for( short index = 1; index < nFields; index++ )
* Q- N9 ]4 C# @' M3 z @$ p/ P{ 2 F W! D# Z% N( z6 C' I
rs.GetFieldValue( index, temp ); 0 L& g3 y2 b) }% V& h6 c
sprintf(buf,"%f",temp.m_dblVal ); % I z6 v4 b4 ~; @" Z! M
UF_UI_write_listing_window(buf );
# I4 S- d6 u3 l5 L' j1 A7 uUF_UI_write_listing_window( "\t" );
# ~( R9 D) n+ E5 O5 c4 ^- X8 o} 6 K6 o8 j @9 R1 m/ G
UF_UI_write_listing_window( "\n" );
% [$ f! F* }' _$ `% D* B& s; wrs.MoveNext( ); : d8 ~, ]3 ?2 K h+ r# p
} + j8 X5 ~) C' J6 E+ _. }( y# H
rs.Close( );// 关闭记录集 ( B. X+ J- j0 y! u/ t
}
1 N) m7 y% Y' s0 n2 M, \Database.Close(); // 关门数据库连接
! W+ \8 G6 x R; d; C} ; b; ~7 j4 Q) p4 r
} ( S! j0 N3 y! W
catch( CDBException *pe ) // 出错处理 6 x8 r' G- f) H" e( a4 {
{
0 v, h. U! M9 UAfxMessageBox( "Exception!" );
+ Y% k" c }! o1 B! u: \0 E0 R1 NAfxMessageBox( pe->m_strError );
3 o# t9 d* g! k+ b$ F5 C) u9 Gpe -> Delete( );
M4 C3 p% I" \ c} * ^# y; h3 p$ q3 B3 t7 G
} + b* B1 |& W# g( v) D+ Y3 E
2.3 通过ADO访问外部数据 ; q6 [; v4 Z" q8 D- a# F6 V6 F
ADO(ActiveX Data Objects)是微软的数据库对象技术,ADO里面包括连接数据库的对象,从查询语句中返回数据的记录集对象和表现数据元素1 H/ @7 y. }$ s
; y0 w# _. n) Z( t; K的字段对象。支持ADO编程的库文件是msado15.dll,它默认保存在“c:\program files\common siles\system\ado\”目录下,动态链接库9 F" f* V5 }% m- E* ~9 Y
4 n# d& V* q- A$ H# a A! f4 ^msado15.dll封装了ADO的所有功能。在默认情况下,Visual C++不支持ADO对象。要在程序中使用ADO对象,需要使用#import命令将ADO库文件
/ ~& a' ~% L8 T& j' O* Q
, X+ F2 K2 [8 s( }导入到工程中,代码如下:
: m3 h0 S! q: b2 z, |#import “c:\Program Files\Common Files\System\ado\msado15.dll” no_namespace rename(“EOF”,”adoEOF”) rename(“BOF”,”
5 A, f, P! O! ]: E5 r# }! }
) Q6 J% B/ p" q, K- I' D* z# [9 YadoBOF”)
5 @; f% _" S' X( x参数no_namespace 表示不使用ADO的名字空间。为了避免出现常量名冲突,需要将EOF改名为adoEOF、BOF改名为adoBOF。 3 g! J/ A3 f: G% j2 f
ADO库包含3个基本接口,即_ConnectionPtr接口、_CommandPtr接口和_RecordsetPtr接口。它们分别对应Connection对象、Command对象和0 W) }0 Z9 \% D0 h
) G7 S; S" }( U4 ]Recordset对象。通过这三个基本接口可实现对数据库的访问。 . ~3 i1 y2 Y8 L, g
通过ADO访问数据库的一般步骤如下:
) \+ t; i4 ]7 B! D. ^0 A V: E(1)连接到数据源; ) E' q( r0 o0 X% D
(2)指定访问数据源的命令(查询、更新、删除等操作命令); 6 g: r3 R+ |# K: ~. y2 U: O
(3)执行命令。 & |+ K" T# v. ]$ C3 p! n
有关ADO库基本接口的使用方法请参见相关的参考手册,下面给出通过ADO访问Access数据库表的实例程序代码段: ; m- J: I4 `3 e6 W1 C# B; I% Q* F
bool DoAdoTest( void ) ' R% d/ `) `9 F
{
. g/ i2 h, M5 ]) v// 初始化对COM的调用
( V; D. o p5 H7 t3 t6 Y# h; H2 ?CoInitialize( 0 ); 6 p6 M. e1 A r) T5 y0 R
_ConnectionPtr pConnection = NULL; // 连接
4 F$ N8 D+ f7 u T5 q, R7 o_RecordsetPtr pRecordset = NULL; // 记录集
1 u+ j# O5 {4 Y6 d6 {HRESULT hr = E_UNEXPECTED;
8 T) T4 ]) Y9 A; v8 A- dCString strConnectionString( "Provider=Microsoft.Jet.OLEDB.4.0;Data 落Source=f:\\ug\\chapter3_4\\screw.mdb" ); // 连接字符串
5 s# @# `# @2 q9 E# SCString strSqlCommandString( "SELECT * From screw_table " ); // SQL语句
: m" }( D/ W4 O2 UpConnection.CreateInstance( __uuidof( Connection ) ); // ( "ADODB.Connection" );
- w% x% a: y `) `) DpRecordset.CreateInstance( __uuidof( Recordset ) ); // ( "ADODB.Recordset" ); . V! j( P0 w8 H$ b5 k# H+ t$ I; ^ D
try ) K l4 H' d7 E& F' s
{ hr = pConnection->Open( ( _bstr_t )strConnectionString, "", "", adModeUnknown ); // 连接数据库
- T$ n" Q1 _$ l6 K2 ?MessageBox( NULL, "连接数据库成功!", "提示", MB_OK | MB_ICONINFORMATION );
: G7 _1 s' \! g} " l) m: r" t6 [* ]* V( S
catch ( _com_error e )
. L/ S/ o/ u/ o9 G P{
6 D$ l9 T7 O1 m5 D- X. h* }MessageBox( NULL, "连接数据库失败!", "错误", MB_OK | MB_ICONERROR ); * b$ v% |3 F: w( H0 A
return false; $ g3 {6 ?2 l# v7 K7 ?/ z6 V5 u8 Q
}
7 {& r6 S m; X- ptry
" L i; U- z" x ?" z0 n; w, q{ 7 k- X: a7 X) p, } {) t4 K" P
hr = pRecordset->Open( ( _bstr_t )strSqlCommandString, $ G, a [1 p# G; x+ B2 H
_variant_t((IDispatch*)pConnection,true),
- r- X6 }+ J- gadOpenStatic,
3 \" u# h, j9 f+ @& ~" IadLockOptimistic,
% r" Y9 ~/ I: U# HadCmdText ); // 获取记录集
: M7 M o7 X$ I, Q) W1 i3 S1 I, d, S}
- u& g" k0 j ]& @; T2 Ucatch ( _com_error* e )
/ {1 r( ~0 q) u1 ?8 S ?" d4 v# M{ ; P |2 G2 \( N
e->ErrorMessage();
- ~0 |% r6 p+ pMessageBox( NULL, "打开记录集失败!", "错误", MB_OK | MB_ICONERROR ); $ ^6 L6 s. ^0 [: t; Z% {* Z
}
, v+ k+ b! ?9 V* c, h. ?CString tmp;
+ e3 r7 g* I1 a' ^/ O- v! g: a+ lUF_UI_open_listing_window(); / r. `- t m2 K( H# ^: L3 s
// 输出字段名 , f' J- F6 l# L; M- T" a
long lFieldsCount = -1; ( w1 N: [6 O+ U8 D& X1 T
lFieldsCount = pRecordset->GetFields()->Count; % l: q$ m% q* k/ ]' l+ \
for ( long i = 0; i < lFieldsCount; i++ ) : p- C) i% [6 ?" ?( E$ I
{
; [% l$ i/ H# X/ F* b$ L/ _tmp.Format( "%-7s", ( LPCSTR )pRecordset->GetFields()->Item[ i ]->Name ); 9 [3 H% J# L, K
UF_UI_write_listing_window( ( LPTSTR )( LPCSTR )tmp );
( u" H2 x4 U$ jUF_UI_write_listing_window( "\t" ); " Z% X. _/ P* C. e
}
9 [2 m* }* i! A% O) xUF_UI_write_listing_window( "\n\n" ); / @7 d) N1 w+ L3 n6 k
// 输出所有记录
2 }0 u) K i0 _pRecordset->MoveFirst();
( C% [; ?6 C" jwhile(!pRecordset->adoEOF)
0 I' o' `$ {0 Z( @" C{
8 M5 s0 I$ m- c' i1 L5 [7 [( ^tmp = pRecordset->GetCollect( 0L );
7 ], y4 S+ ? d% Y" `UF_UI_write_listing_window( ( LPTSTR )( LPCSTR )tmp ); $ s7 K* P. d% B8 l' p# l
……//输出记录中其他字段值 & y: R R2 H5 R) f
pRecordset->MoveNext();
5 R* a" o- @6 ]5 q/ l1 U}
* H. W9 F% h0 P1 PpRecordset->Close(); ) I8 _. }" f# _/ D3 R! e4 X
pRecordset = NULL;
+ D2 {. v. w# RpConnection->Close();
) F" Q W$ O. v E0 kpConnection = NULL;
' }6 \9 @3 |4 t/ m3 a9 dCoUninitialize();
1 }2 }$ s' q: A. a V6 K2 greturn true;
$ }0 l4 h8 G( ~$ K* ~1 X} # ]9 [7 t9 l5 J8 J) S: m" K
3 结论
% q# V6 w" z9 i7 l, t% T2 r在UG二次开发过程中,确定选择哪种方法访问外部数据,取决于具体的应用系统要求。通过UG/OPEN API编程较适合于对外部文本文件的访问
" R& @8 h# N/ v- Q! E
, I- q1 c! A( X/ f,可方便实现用户与UG信息窗口交互等功能;通过ODBC和ADO技术可以访问各种支持的数据源,包括文本文件、Excel表及各种关系型数据库表
( S7 ? g, Z5 ]+ o. L( V; c7 W' ~) Q9 J! |' Y. W8 d
等,ADO与ODBC相比,使用更加简便,免去了繁琐的配置数据源工作,但有些数据库仅支持ODBC,不直接支持ADO数据库技术 |
|