|
ug二次开发中外部数据访问方法研究 1 前言
2 z V& ]# B- p" R! b4 L8 Z随着UG系统的推广和普及应用,基于UG平台的二次开发工作显得越来越重要,在UG的二次开发应用系统中,经常需要与各种外部数据打交道,
! U e7 l: q9 o* ^9 _7 z6 v
* o& l6 O6 B2 C; T2 Y8 L$ Z7 ^UG/OPEN API提供了丰富的文件访问操作函数,利用这些操作函数及VC++的MFC类库,可以方便地实现外部数据读写访问编程。
& r6 s6 m2 c2 W R/ m. g2 外部数据访问的主要方法 3 |9 A$ O! ` I1 N& s! J8 ]
在UG二次开发应用系统中,主要访问的外部数据有文本文件、Excel表、关系型数据库表等,通常可以通过以下方法访问这些外部数据: 3 `; ]+ |( U$ @4 f9 a5 [
(1)通过UG/OPEN API提供的文件操作函数访问外部数据
9 n, D4 ?6 O% j/ ^$ M6 g* C(2)通过ODBC数据源访问外部数据
6 A9 |& w$ m1 ]/ N/ j* e(3)通过ADO访问外部数据 " g, |6 I w4 @6 h! B
2.1 通过UG/OPEN API提供的文件操作函数访问文本文件数据
# I8 t8 A' g2 X/ r2 K0 y! iUG/OPEN API中有关文件操作的函数包含在头文件uf_cfi.h中,通过函数uc4500可以打开二进制文件,相关的文件操作函数有uc4510、uc4511
- b4 [" Z( E3 v" H/ _6 t, y2 b3 a W, V8 b8 A* F0 J
、uc4512、uc4513及uc4520、uc4521、uc4522、uc4523,通过函数uc4504可以打开文本文件,相关的文件操作函数有uc4514、uc4524、uc4525# _2 E6 u% ~( a# I! T; p
: ?, F1 _/ o* \& R; `; B
,函数uc4540用于关闭文件,判断文件是否存在使用函数UF_CFI_ask_file_exist。 8 f- B5 h3 H7 W
通过UG/OPEN API提供的文件操作函数访问外部数据时,要注意以下问题:
: u* y, q# A! \6 ]" l(1)UG/Manager 和 IMAN中的文件和文件夹操作不能使用uf_cfi.h中函数; 5 i: @" o' A6 e5 K: X/ h
(2)UG/OPEN API中对文件和文件夹标识符的长度有如下限制: 5 U( J" c8 y% r3 V. k1 z( [
文件名长度不能超过UF_CFI_MAX_FILE_NAME_LEN;文件夹路径的长度不能超过UF_CFI_MAX_PATH_NAME_LEN;整个文件路径的长度不能超过. J5 M4 a: f2 r9 l( I: F/ j. Z
7 V5 ]. }0 M& _: u
UF_CFI_MAX_PATH_NAME_LEN。
: J5 F0 h7 I+ \; r A: Y% M访问文本文件的程序流程如下图:
- u% r8 n& p0 w( p5 O2 k: v
, W1 B0 X; {6 r9 l0 ?2 e6 A2.2 通过ODBC数据源访问Excel表或关系型数据库表数据
5 m& N' K5 p6 t( T q( ~) m" h) e E: pODBC(Open Database connectivity 开放式数据库互连)是由微软公司提出的一个用于访问数据库的统一界面标准,它提供了一个一致的应
, x* o' |2 G. J
$ o+ y1 h% l6 P% \6 M ?# b用程序编程接口,该接口使用一个针对数据库的驱动程序与不同的数据库协同工作。 $ r( e) f$ x/ j& `& C; x2 K% \
通过ODBC访问外部数据时,需要先指定访问的数据源DSN(Data Source Name),以指定ODBC与相关的驱动程序相对应的入口。在控制面板的
6 t6 p4 |2 c7 D% E7 z8 [( D: s/ C9 P: S+ W. @- G5 o! c9 Y8 Z
管理工具中可以打开ODBC数据源管理器,指定DSN。 " g4 y( p+ ~# d
建立MFC数据库类Cdatabse对象可以实现对外部数据的访问编程。一个CDatabase对象代表与数据源的一个连接。创建一个CDatabase对象之后( n4 n2 G- I3 U5 S* l3 {
4 Z4 P0 d# Z4 R0 @,调用Open或OpenEx成员函数指定一个DSN,就建立起了与DSN的底层数据源的连接(打开数据库)。成员函数Close关闭数据库。CDatabase对+ T, B+ b/ z& M
) ^7 v- \6 M8 C: v6 M$ m
象通常与一个或多个记录集(CRecordset对象)一起使用,通过CRecordset类的各成员函数完成对数据源的读写操作。 " u1 {: v; v* P/ M: j5 b `3 |0 S% d
通过ODBC访问一个Excel表的编程实例代码如下: - P& ?* {$ X1 ~
static void do_ugopen_api(void)
, ], c) B. V: b9 ?6 J( E{ " I5 x5 X5 ]( l( v' C! Z- j( @% n
CDatabase Database; // 定义一个MFC的CDatabse数据库类对象Databse . d% X) C! Q, ?" E" Q0 `0 O
CString SQLCommand = "select `Serial_Number`, `Outer_Diameter`, `Inner_Diameter`,`Height` from `Sheet1$`"; // SQL查询语句
& Y" C8 A7 k. {7 ^" jDWORD dwOptions = 0;// 设置连接的建立方式 R) J! e- E+ b
CDBVariant temp;// 数据库数据通用类型 7 x6 P1 ~$ m& `2 t( N$ h
int result; // 储存返回值的变量
4 T; ]1 C# y( H8 b ychar buf[133]; * j9 J1 ]6 i$ N9 L
try 8 ` Z+ H9 B& I
{ 8 e: o$ b* ]( W, k" k; e
result = Database.OpenEx( "DSN=Standard Part", dwOptions ); // 打开数据库
9 N& E* J" z/ F4 ^2 pif( result != 0 ) // 如果成功打开
/ O# L1 M7 D! f. r8 L{ * W# F" X& u e% q
CRecordset rs( &Database ); // 定义记录集
8 ]. |( H) l. C2 \' y, ^2 Z6 O+ R. {if ( rs.Open( CRecordset::snapshot, SQLCommand ) != false )
) b' B! ]3 w L, ?" }{
8 `) n2 q8 `& q: Y) O/ N! y$ w/ M+ zrs.MoveFirst( );
5 { e- }4 v$ |& _) h: y7 f( N& c" Tshort nFields = rs.GetODBCFieldCount( );// 获取记录的字段数目 : b. h, ~" T; y) ?* ^$ A4 X
UF_UI_open_listing_window( ); ! Y- w! }# c+ W% p5 E0 ^
while( !rs.IsEOF( ) )
N# w( \/ c2 }; z$ `{ ! P/ g2 d+ d6 V) C9 A2 {$ m
for( short index = 1; index < nFields; index++ )
4 A2 L7 n [+ z" `{
# e) G4 U/ U( k7 j/ krs.GetFieldValue( index, temp ); 6 R2 `1 J& H' o0 G
sprintf(buf,"%f",temp.m_dblVal );
2 q0 h) f3 ^" s+ z( P: S1 `3 Z gUF_UI_write_listing_window(buf ); ) V4 D q2 V0 |, I
UF_UI_write_listing_window( "\t" );
% u3 d( F7 t& p- n; B; C" T5 Q# h}
' R+ K! S! K$ X* `UF_UI_write_listing_window( "\n" ); 4 d. l3 r( N( N
rs.MoveNext( );
2 J. m7 k) d0 ~/ @8 M}
: O) E) }% ^9 L# M9 o! K; Yrs.Close( );// 关闭记录集 7 G( k& m& d( e7 ]: s
} ! D+ F. I+ }" o6 G5 m; R% G, a
Database.Close(); // 关门数据库连接 $ d8 l) U% S8 f2 t( b* c3 H
} : n3 q" y, p1 g k- a+ t) l
}
- r! a) ]+ g7 J. fcatch( CDBException *pe ) // 出错处理 : B3 O0 ^: W* K& Q! H z* D
{
! ^- U/ n0 L, cAfxMessageBox( "Exception!" ); C- n* m1 n6 t, J! O
AfxMessageBox( pe->m_strError );
% k$ c& l$ ^( h/ y; N8 l- I4 W: Rpe -> Delete( ); $ P9 F% m# g- K4 U
} 7 u3 m, D9 Z% |
} . \7 N# n m/ ^
2.3 通过ADO访问外部数据
C1 [( s1 A' H0 ]' p) `ADO(ActiveX Data Objects)是微软的数据库对象技术,ADO里面包括连接数据库的对象,从查询语句中返回数据的记录集对象和表现数据元素; c. v& _' J* G4 u1 A+ @& P* B
+ L* ~% o5 q: p. J的字段对象。支持ADO编程的库文件是msado15.dll,它默认保存在“c:\program files\common siles\system\ado\”目录下,动态链接库
% [/ n% g% V: V/ w' V9 m+ \1 ?, i/ U% y% w8 k5 H& s
msado15.dll封装了ADO的所有功能。在默认情况下,Visual C++不支持ADO对象。要在程序中使用ADO对象,需要使用#import命令将ADO库文件
4 U, x$ @: p8 O0 s3 s! a- R( {2 U3 v+ K4 f5 G3 @
导入到工程中,代码如下:
9 y, Y/ l9 n; X5 J o( [! J#import “c:\Program Files\Common Files\System\ado\msado15.dll” no_namespace rename(“EOF”,”adoEOF”) rename(“BOF”,”
1 k' E/ P; z9 E- B5 [ `6 _
/ F) l0 Z; ~, v" N" r- UadoBOF”) + s i' [) K; J( f# Q& k) t: v
参数no_namespace 表示不使用ADO的名字空间。为了避免出现常量名冲突,需要将EOF改名为adoEOF、BOF改名为adoBOF。 ( f4 v5 N8 R" F5 x' V, J
ADO库包含3个基本接口,即_ConnectionPtr接口、_CommandPtr接口和_RecordsetPtr接口。它们分别对应Connection对象、Command对象和2 A: h5 e% v1 k: M7 z2 D& U
: g. N8 i. r6 u' S4 }( lRecordset对象。通过这三个基本接口可实现对数据库的访问。
/ M. @3 E3 X2 i! f4 a: Q通过ADO访问数据库的一般步骤如下:
6 n, h3 K8 o7 _3 r, d(1)连接到数据源; 8 p: Q& V( t, @. z, t$ p, k! A
(2)指定访问数据源的命令(查询、更新、删除等操作命令); # ?( D$ r8 V$ Z( I
(3)执行命令。 ; a, }9 `+ O4 R( f3 Q
有关ADO库基本接口的使用方法请参见相关的参考手册,下面给出通过ADO访问Access数据库表的实例程序代码段: 0 R4 R8 z9 z" K% r) C, E
bool DoAdoTest( void ) / |, N4 q) d5 n- U, u
{ - m/ _8 x1 z8 F. C, b# m
// 初始化对COM的调用
( N+ v8 n8 ~9 R' ICoInitialize( 0 );
4 \' m1 @# k, p; q) J_ConnectionPtr pConnection = NULL; // 连接
% W6 x: F- e; @; J7 E_RecordsetPtr pRecordset = NULL; // 记录集 ( E5 j" e$ [. o2 |8 m
HRESULT hr = E_UNEXPECTED; / O& a3 E3 d: t! x3 _* X- {
CString strConnectionString( "Provider=Microsoft.Jet.OLEDB.4.0;Data 落Source=f:\\ug\\chapter3_4\\screw.mdb" ); // 连接字符串
+ E* P5 S3 b; B" a& eCString strSqlCommandString( "SELECT * From screw_table " ); // SQL语句
& x4 }# X$ m+ W# }3 L1 ppConnection.CreateInstance( __uuidof( Connection ) ); // ( "ADODB.Connection" );
3 o. N( b. E% u0 I Z% Q" L& `1 [+ `pRecordset.CreateInstance( __uuidof( Recordset ) ); // ( "ADODB.Recordset" ); ; `" }" q6 i" Q2 m" d
try
' j9 D0 p% r$ u l( k+ I{ hr = pConnection->Open( ( _bstr_t )strConnectionString, "", "", adModeUnknown ); // 连接数据库 : f8 K2 a( @7 y* s+ u2 i. T
MessageBox( NULL, "连接数据库成功!", "提示", MB_OK | MB_ICONINFORMATION );
7 H% K$ a* e# i1 }0 m4 y9 A( v} / P7 h$ Q# {! l3 V; D* u2 ^: ]1 y
catch ( _com_error e ) o5 d9 x$ {& V
{
# S1 b0 p9 N3 N; L, tMessageBox( NULL, "连接数据库失败!", "错误", MB_OK | MB_ICONERROR );
, n/ }6 s, @( ?4 treturn false;
- Y% E# Q& T, M3 V! a" U3 n}
" t: Q t- ~2 C, ^9 y: j; p. o2 wtry
2 {7 { L$ S" P# V% Z. W{
0 k- a" [ z! b$ T v* F: mhr = pRecordset->Open( ( _bstr_t )strSqlCommandString,
9 _/ {4 d0 `' x$ Z( h$ _3 a_variant_t((IDispatch*)pConnection,true), / i, G* |+ W2 @% f
adOpenStatic,
2 R: ^7 G Q g. V5 D8 N* MadLockOptimistic,
. D& T$ T, K: O& i' F1 jadCmdText ); // 获取记录集
+ @6 _. g* l/ l- _5 A} # ^% x# U/ d$ `3 v
catch ( _com_error* e ) . _& A0 S: v( L
{
8 n+ N N& [, E9 m7 R0 b* X- qe->ErrorMessage(); + b% W6 i2 O" ~& R V
MessageBox( NULL, "打开记录集失败!", "错误", MB_OK | MB_ICONERROR );
3 z5 l* @' E* P+ ^: i& t}
* G% P5 m3 |, X& F3 YCString tmp;
# V# K& S+ S) u6 J MUF_UI_open_listing_window(); 4 c X- a# J% Z/ {+ J5 ]* e
// 输出字段名 - m' D( y: N, w9 L% h. A
long lFieldsCount = -1;
) d* [3 }% ]( j6 P) H% ?lFieldsCount = pRecordset->GetFields()->Count;
+ M5 T0 l4 R* T% D' |for ( long i = 0; i < lFieldsCount; i++ )
8 ~# n# H7 O% B# f: h5 J{ ! ^3 `" {- v( B" F% j b
tmp.Format( "%-7s", ( LPCSTR )pRecordset->GetFields()->Item[ i ]->Name );
) Y) i+ \$ U' V, ?6 iUF_UI_write_listing_window( ( LPTSTR )( LPCSTR )tmp );
8 U) z: p4 U. G; X7 LUF_UI_write_listing_window( "\t" ); # q! O2 j8 j% E. {6 ?$ T& T
} # v7 R, L3 {$ B$ G, w& R" N( r6 F2 S
UF_UI_write_listing_window( "\n\n" );
" P+ \/ D8 `5 @: o// 输出所有记录
1 U4 j1 A& O2 epRecordset->MoveFirst(); " A# o7 I- K1 w. K( T
while(!pRecordset->adoEOF) 0 w# T4 |, ~1 i5 s
{ 2 D5 x5 m; c7 d& l- y; W
tmp = pRecordset->GetCollect( 0L ); & P, c- d: b& Z- @
UF_UI_write_listing_window( ( LPTSTR )( LPCSTR )tmp ); % T' v) c5 C' ^+ F. w$ |' x
……//输出记录中其他字段值 ! u" Z, i1 v: L" F/ d; X/ @9 _8 @! j) K
pRecordset->MoveNext(); / H s W2 i. p% `) l L$ T
} / N \5 s/ P8 k; T1 w0 M0 h6 t
pRecordset->Close();
h# v1 Z& a5 HpRecordset = NULL; 6 \/ y/ [- y8 Q0 A, y
pConnection->Close(); 5 A) D- I5 Z" d
pConnection = NULL;
3 W/ K6 |6 E" I+ ^6 W, M1 e UCoUninitialize();
$ Z! n f* o. y: |6 M: ]$ K8 f. nreturn true;
* C/ r& ^8 L9 f5 @" O5 E6 U} - g) x4 n. H2 y# r: U; w
3 结论
2 m. O7 Q, S! g在UG二次开发过程中,确定选择哪种方法访问外部数据,取决于具体的应用系统要求。通过UG/OPEN API编程较适合于对外部文本文件的访问
9 d$ O J& N( Z. a/ K n X: I$ X# V+ S/ k# r4 m# t
,可方便实现用户与UG信息窗口交互等功能;通过ODBC和ADO技术可以访问各种支持的数据源,包括文本文件、Excel表及各种关系型数据库表7 y' g, C0 _2 u, E3 }; Y$ ?
# t0 g5 F( S9 A7 L等,ADO与ODBC相比,使用更加简便,免去了繁琐的配置数据源工作,但有些数据库仅支持ODBC,不直接支持ADO数据库技术 |
|