|
ug二次开发中外部数据访问方法研究 1 前言 , s1 y5 H( o( n
随着UG系统的推广和普及应用,基于UG平台的二次开发工作显得越来越重要,在UG的二次开发应用系统中,经常需要与各种外部数据打交道,
( P0 `4 o" W x- H: [ X- {! C0 |; D- R
UG/OPEN API提供了丰富的文件访问操作函数,利用这些操作函数及VC++的MFC类库,可以方便地实现外部数据读写访问编程。
|6 H4 L/ g- ?0 Q2 外部数据访问的主要方法
1 i: d; e2 _3 [4 O- D4 L/ y在UG二次开发应用系统中,主要访问的外部数据有文本文件、Excel表、关系型数据库表等,通常可以通过以下方法访问这些外部数据: + `3 F6 J" p- x6 K; Z7 G
(1)通过UG/OPEN API提供的文件操作函数访问外部数据 0 R( C. d h. _& \" h
(2)通过ODBC数据源访问外部数据 ) s9 P! w: @/ @5 U0 {
(3)通过ADO访问外部数据 8 M* N9 S! h7 A/ ~
2.1 通过UG/OPEN API提供的文件操作函数访问文本文件数据 ' I" Z* A' ?, ~7 j
UG/OPEN API中有关文件操作的函数包含在头文件uf_cfi.h中,通过函数uc4500可以打开二进制文件,相关的文件操作函数有uc4510、uc4511
2 Q2 n( R x0 z6 f+ v0 D9 P3 L# C
、uc4512、uc4513及uc4520、uc4521、uc4522、uc4523,通过函数uc4504可以打开文本文件,相关的文件操作函数有uc4514、uc4524、uc4525) ?+ O" I9 g M2 r/ y/ I! H+ v
3 x+ m" o# q. D, S) ~
,函数uc4540用于关闭文件,判断文件是否存在使用函数UF_CFI_ask_file_exist。
, j0 X( ?. p) M' W* Q$ T3 ~( c+ q通过UG/OPEN API提供的文件操作函数访问外部数据时,要注意以下问题:
# O0 S) }! z- g @4 P(1)UG/Manager 和 IMAN中的文件和文件夹操作不能使用uf_cfi.h中函数;
# R2 B x. n0 p8 }* x1 Q(2)UG/OPEN API中对文件和文件夹标识符的长度有如下限制:
1 e2 V( S5 B/ ]1 {" P文件名长度不能超过UF_CFI_MAX_FILE_NAME_LEN;文件夹路径的长度不能超过UF_CFI_MAX_PATH_NAME_LEN;整个文件路径的长度不能超过3 v$ s" i0 y$ U0 w; d" d, G+ J9 Z7 T
: E) ]) G) v* e# P# Z1 `' ?1 bUF_CFI_MAX_PATH_NAME_LEN。
+ V u8 _1 H3 A& F, }3 q7 h访问文本文件的程序流程如下图: , _* q/ E% ~" k5 n$ Y% {
/ u7 \; B& x1 v p2.2 通过ODBC数据源访问Excel表或关系型数据库表数据
& U4 i0 Q0 U: @2 v8 M/ {ODBC(Open Database connectivity 开放式数据库互连)是由微软公司提出的一个用于访问数据库的统一界面标准,它提供了一个一致的应
; i3 R9 p8 ~4 Y3 E/ q3 `, z
4 ?# l: z9 {7 }) {* o0 w用程序编程接口,该接口使用一个针对数据库的驱动程序与不同的数据库协同工作。
" W" P* P& J3 q6 i2 |# G通过ODBC访问外部数据时,需要先指定访问的数据源DSN(Data Source Name),以指定ODBC与相关的驱动程序相对应的入口。在控制面板的& f N: V$ n2 M* {$ h
+ {9 ^2 s" i9 {( \% u管理工具中可以打开ODBC数据源管理器,指定DSN。
E: B9 E6 e. ]3 Y; L, d* ]+ O建立MFC数据库类Cdatabse对象可以实现对外部数据的访问编程。一个CDatabase对象代表与数据源的一个连接。创建一个CDatabase对象之后
- o, n8 ~/ j0 F' G$ N: }
* t h0 R9 I- C ~2 h5 S& S,调用Open或OpenEx成员函数指定一个DSN,就建立起了与DSN的底层数据源的连接(打开数据库)。成员函数Close关闭数据库。CDatabase对
" H: ~( t+ H ?
6 Y# C7 K8 Y! V4 ^0 q/ r) G象通常与一个或多个记录集(CRecordset对象)一起使用,通过CRecordset类的各成员函数完成对数据源的读写操作。
4 ]+ j: P6 T% C3 ]: j9 J通过ODBC访问一个Excel表的编程实例代码如下: 4 }- t( i2 Z/ U# @7 `
static void do_ugopen_api(void)
& a: {+ P2 D( P1 M/ y5 V{
# c6 T9 D' E7 B c6 JCDatabase Database; // 定义一个MFC的CDatabse数据库类对象Databse
& q! H3 v! m) m. A' a3 jCString SQLCommand = "select `Serial_Number`, `Outer_Diameter`, `Inner_Diameter`,`Height` from `Sheet1$`"; // SQL查询语句
9 z% ^ T3 u$ @7 ~/ D O( bDWORD dwOptions = 0;// 设置连接的建立方式
' J, s9 [1 ~9 X5 wCDBVariant temp;// 数据库数据通用类型 5 ?; I6 S& a2 r/ w S8 r5 P+ O# M/ i3 }
int result; // 储存返回值的变量 - E7 ~! b% j* |$ B6 c+ b0 P
char buf[133]; ! J: z: w+ M( `5 X) @3 ?! q
try
0 |1 J8 z* V( l' w1 B0 o+ l{ : Y! G: e( X# s0 C* e5 D0 t
result = Database.OpenEx( "DSN=Standard Part", dwOptions ); // 打开数据库 / A0 Q$ w! d& f* }7 X7 d O4 J1 C" e3 O
if( result != 0 ) // 如果成功打开 1 |& X. ]8 b U1 N, X
{ # T3 U$ i/ i1 }* q2 q
CRecordset rs( &Database ); // 定义记录集
5 w5 D4 h2 x# L+ S+ b) ]$ r, ~if ( rs.Open( CRecordset::snapshot, SQLCommand ) != false )
( _; M# G. E" r% w& F{ ( H0 y0 F& s' \! f/ }0 [) |; m; s
rs.MoveFirst( );
7 O2 W9 ]) j: w5 B1 d! ^1 Fshort nFields = rs.GetODBCFieldCount( );// 获取记录的字段数目
4 X6 I# ?6 E! I6 A4 y( Y- S; UUF_UI_open_listing_window( ); 5 }; l; Z q6 i. \# q+ K' t
while( !rs.IsEOF( ) )
# N' m2 b0 @) ]6 O' R' c! |/ z* j G{
% Y# z7 k+ Q/ p9 M5 Ffor( short index = 1; index < nFields; index++ )
4 W" @1 D+ L! X' X6 e- `{
) F- l7 J' i' f% f/ c# k, c0 grs.GetFieldValue( index, temp );
$ N' u( V6 G: Y6 k4 F8 ?sprintf(buf,"%f",temp.m_dblVal );
" m ]6 r$ w- c( W4 NUF_UI_write_listing_window(buf );
; f5 l) m* J7 \% X- b' h4 z. U) @UF_UI_write_listing_window( "\t" ); + V. g- v) Q4 ^- @. L. n! \* |
} 1 ?# b& k9 k% n7 q0 s
UF_UI_write_listing_window( "\n" ); # V `8 r3 @1 m/ s6 D) S* }& |
rs.MoveNext( ); ( a' y+ `: H3 g9 b2 B
}
& f$ _; j# ?9 M) a3 ^% d3 Irs.Close( );// 关闭记录集 1 e8 Q- R9 z8 h w$ Z! n8 i
} 1 l& [. v7 Z% ?0 x9 k
Database.Close(); // 关门数据库连接 5 `! d$ u2 P9 J9 O. F( x$ Y( B5 R. `5 G
} 8 I) v% x# T9 @: Y& h$ S9 j
} 4 f8 Y8 i0 V4 l) Y! @
catch( CDBException *pe ) // 出错处理
& \9 V( O9 r$ `: j{ ' q5 _& Q! \6 C# m
AfxMessageBox( "Exception!" );
- J# \; A6 ?- I; d; p8 `AfxMessageBox( pe->m_strError );
1 @4 H0 P% j* Qpe -> Delete( );
% S6 Y W, _$ k# Z( d" h; O# c}
; w3 [2 L2 ]8 v3 |} ' W$ o8 f3 J. J9 I5 m( O3 u" F
2.3 通过ADO访问外部数据 & K1 C# o/ X% V) H+ Y( b) t
ADO(ActiveX Data Objects)是微软的数据库对象技术,ADO里面包括连接数据库的对象,从查询语句中返回数据的记录集对象和表现数据元素$ Y+ S8 D( ^2 N4 e! ]. f4 X& ~
& f( ?( `7 M! K8 Y" a; U: s
的字段对象。支持ADO编程的库文件是msado15.dll,它默认保存在“c:\program files\common siles\system\ado\”目录下,动态链接库! D" m/ B' ] j; E3 u
+ ~% `1 }( N" x# A1 v0 g/ ?" imsado15.dll封装了ADO的所有功能。在默认情况下,Visual C++不支持ADO对象。要在程序中使用ADO对象,需要使用#import命令将ADO库文件4 b1 K# R1 L n* s* ] }9 F$ ]) f2 h
: _; ~& c7 X; }& R导入到工程中,代码如下: ( }4 x ~5 k" O a# K+ A: z
#import “c:\Program Files\Common Files\System\ado\msado15.dll” no_namespace rename(“EOF”,”adoEOF”) rename(“BOF”,”4 R* f6 @, @8 _1 _& U' w* g
; [! d5 B7 Q8 A- padoBOF”) - v( Q- @6 F9 W' {
参数no_namespace 表示不使用ADO的名字空间。为了避免出现常量名冲突,需要将EOF改名为adoEOF、BOF改名为adoBOF。 $ D$ D! I0 q* H5 B
ADO库包含3个基本接口,即_ConnectionPtr接口、_CommandPtr接口和_RecordsetPtr接口。它们分别对应Connection对象、Command对象和$ s) Z8 P( H/ w$ \, V/ _
" h1 W1 g8 z1 jRecordset对象。通过这三个基本接口可实现对数据库的访问。 + j8 J* v L; ^( g- J# G
通过ADO访问数据库的一般步骤如下:
F# U* k' P, y* a(1)连接到数据源; `. ^5 o0 l8 @ L! ]
(2)指定访问数据源的命令(查询、更新、删除等操作命令);
p% S6 M: V7 k! c0 f6 I(3)执行命令。
2 ?6 E: \) c) n8 G5 @ f有关ADO库基本接口的使用方法请参见相关的参考手册,下面给出通过ADO访问Access数据库表的实例程序代码段: / O5 D+ ^5 k+ K3 @+ b
bool DoAdoTest( void ) 3 z# ~- D/ Q; b: f% R2 _
{ 3 q( l' |- m0 b/ V; c" s" L0 \
// 初始化对COM的调用 * n3 r( X. P" m+ d$ h
CoInitialize( 0 ); 9 q) p! c0 w/ i
_ConnectionPtr pConnection = NULL; // 连接
) ?, k4 \. r2 n& N6 q8 ~_RecordsetPtr pRecordset = NULL; // 记录集
, X1 z) w/ I4 ?" h9 W: uHRESULT hr = E_UNEXPECTED;
, {1 j* A( \( V1 Q! r& ZCString strConnectionString( "Provider=Microsoft.Jet.OLEDB.4.0;Data 落Source=f:\\ug\\chapter3_4\\screw.mdb" ); // 连接字符串
" n) t* {+ ]! @0 h6 UCString strSqlCommandString( "SELECT * From screw_table " ); // SQL语句
# u% e! s/ n8 O, C3 ^1 T/ zpConnection.CreateInstance( __uuidof( Connection ) ); // ( "ADODB.Connection" );
' J0 q9 l3 M) OpRecordset.CreateInstance( __uuidof( Recordset ) ); // ( "ADODB.Recordset" );
, X) W0 F0 e* T2 \try ! S- q7 O6 D/ t4 p$ P0 H3 K4 w
{ hr = pConnection->Open( ( _bstr_t )strConnectionString, "", "", adModeUnknown ); // 连接数据库
- F- o7 B- Z1 d# DMessageBox( NULL, "连接数据库成功!", "提示", MB_OK | MB_ICONINFORMATION ); N& U" r2 L. a. {- h3 _6 W
}
: t7 H8 t) Q% ]catch ( _com_error e ) / p. W* w7 M+ Y( \
{
5 g5 n; I( `: r- U$ h) O' n7 NMessageBox( NULL, "连接数据库失败!", "错误", MB_OK | MB_ICONERROR ); . ^2 {% T! I3 q" ~; g& Y
return false;
8 l- C1 l# w o}
+ F* _: E K5 ~$ etry
- ^, Q$ ~8 E* G% M( S( |$ Q$ c+ p a{
0 l7 F: ]. A) J8 t0 L7 Ihr = pRecordset->Open( ( _bstr_t )strSqlCommandString,
( @' r; D/ W8 J' F_variant_t((IDispatch*)pConnection,true), # ^5 _4 g. d7 z- z) _
adOpenStatic,
( _ Z8 L9 i# s: \& B% iadLockOptimistic, 5 a# \7 q) L, d; v* a& u5 F5 ^
adCmdText ); // 获取记录集 $ n3 M9 q! F# j1 {3 ^& A
}
* |0 j$ D" K; a- H; y7 s) Scatch ( _com_error* e )
# Y* R; X7 U( s{ ( h X% x) Z3 `
e->ErrorMessage();
: B; p: d X+ SMessageBox( NULL, "打开记录集失败!", "错误", MB_OK | MB_ICONERROR ); ' }; p7 O V# y$ @6 I& _- }1 g
} ; Z. k* F1 W& @) p7 }5 c8 B
CString tmp;
: o1 I8 @. A2 {8 Q6 r1 T' \UF_UI_open_listing_window();
: o* }' R" g r// 输出字段名 8 p: _2 K8 }( {$ N- d1 d, N i
long lFieldsCount = -1; , @& `+ w2 M% h9 J8 L E
lFieldsCount = pRecordset->GetFields()->Count; ' Q( G7 l8 k: \1 c! n% M/ u5 @
for ( long i = 0; i < lFieldsCount; i++ ) / G7 u1 W3 b9 h4 p, |0 ~ z
{ 0 V/ e8 N% N: d0 E4 ]' J$ c8 Z. p
tmp.Format( "%-7s", ( LPCSTR )pRecordset->GetFields()->Item[ i ]->Name );
, n/ z+ y9 \8 m: x* g: rUF_UI_write_listing_window( ( LPTSTR )( LPCSTR )tmp ); 1 _5 ^: Y* J: h! ^& [
UF_UI_write_listing_window( "\t" ); , C- A9 y2 g& E |# x9 h
}
8 l; b0 i7 R; \; y0 Y' xUF_UI_write_listing_window( "\n\n" ); 8 \/ ?% D4 V, I# q3 q
// 输出所有记录
+ L# S5 p# Z. z8 ZpRecordset->MoveFirst(); % i! [0 G6 ~5 W0 S
while(!pRecordset->adoEOF)
# ~, Y8 P5 C6 k, w @/ Q9 N{
7 \9 y0 p: e$ s" Otmp = pRecordset->GetCollect( 0L );
; G' @) O9 T( n+ ~ A! hUF_UI_write_listing_window( ( LPTSTR )( LPCSTR )tmp );
}) s+ L7 l, \0 b* o5 y! F# T……//输出记录中其他字段值
/ `$ e& Z6 G2 S* a% Z- U0 kpRecordset->MoveNext();
" ]5 q' V R5 g7 b. P+ y; g. Q}
4 F6 Z: }% Q. ?1 W4 X) \- TpRecordset->Close();
9 H+ r; g' q) F E* |) o" f" wpRecordset = NULL;
/ S2 i e/ p; O9 T- RpConnection->Close();
3 ~2 `. v0 F. @/ F* _: O) NpConnection = NULL;
4 m: K5 H) B) iCoUninitialize(); 1 O3 F: h% F$ P7 o+ g& Y
return true; ! O0 s: n; O+ m p; y
}
; I( o, v/ }/ R8 g1 s3 结论
) {* M% ]- l$ |) N- G. b4 W在UG二次开发过程中,确定选择哪种方法访问外部数据,取决于具体的应用系统要求。通过UG/OPEN API编程较适合于对外部文本文件的访问
, C. Y& \! t7 j+ w8 G
. [ T# j# F; M# a,可方便实现用户与UG信息窗口交互等功能;通过ODBC和ADO技术可以访问各种支持的数据源,包括文本文件、Excel表及各种关系型数据库表! x/ @' ]& R+ \* J$ b- Q) k2 s
8 B$ p0 C5 V/ Q7 @. n4 G等,ADO与ODBC相比,使用更加简便,免去了繁琐的配置数据源工作,但有些数据库仅支持ODBC,不直接支持ADO数据库技术 |
|