|
ug二次开发中外部数据访问方法研究 1 前言
# x' @$ J* g6 i+ C) |6 l$ Y随着UG系统的推广和普及应用,基于UG平台的二次开发工作显得越来越重要,在UG的二次开发应用系统中,经常需要与各种外部数据打交道,
9 Z8 v# H- \$ [9 `9 D0 @4 T5 }$ D5 _5 Z6 _6 t. \) c
UG/OPEN API提供了丰富的文件访问操作函数,利用这些操作函数及VC++的MFC类库,可以方便地实现外部数据读写访问编程。 - i( u, R' o: o* f; q* V
2 外部数据访问的主要方法
4 b8 F) j- | e& E+ E! ?在UG二次开发应用系统中,主要访问的外部数据有文本文件、Excel表、关系型数据库表等,通常可以通过以下方法访问这些外部数据: 6 ], R2 e1 {8 p
(1)通过UG/OPEN API提供的文件操作函数访问外部数据 5 D$ N$ i6 {; m# M/ e
(2)通过ODBC数据源访问外部数据
7 n+ X, a- ^4 [3 \7 X# _(3)通过ADO访问外部数据
: {5 U1 Q6 C+ E6 g8 ~- U2.1 通过UG/OPEN API提供的文件操作函数访问文本文件数据 " E7 ?5 q! @, k' ~ \; q
UG/OPEN API中有关文件操作的函数包含在头文件uf_cfi.h中,通过函数uc4500可以打开二进制文件,相关的文件操作函数有uc4510、uc45116 d/ ]% v X- g/ c
( D, b) w2 c7 c# l! K+ t& _0 @4 W、uc4512、uc4513及uc4520、uc4521、uc4522、uc4523,通过函数uc4504可以打开文本文件,相关的文件操作函数有uc4514、uc4524、uc4525
3 m- J9 \3 A; b+ c& s: y$ R+ [4 i% E" Y* A" m
,函数uc4540用于关闭文件,判断文件是否存在使用函数UF_CFI_ask_file_exist。 8 y9 V$ u$ `6 C( f
通过UG/OPEN API提供的文件操作函数访问外部数据时,要注意以下问题:
8 ?6 h1 y6 b# U- N8 c% ]/ h. {(1)UG/Manager 和 IMAN中的文件和文件夹操作不能使用uf_cfi.h中函数;
7 {$ U& w* G ?; f. f$ V5 x% C(2)UG/OPEN API中对文件和文件夹标识符的长度有如下限制:
5 M8 C, h9 ]) n7 I9 m% }6 `文件名长度不能超过UF_CFI_MAX_FILE_NAME_LEN;文件夹路径的长度不能超过UF_CFI_MAX_PATH_NAME_LEN;整个文件路径的长度不能超过4 A k3 U! y- A) z
: |9 E/ i9 i9 `- U; s. }- s3 V
UF_CFI_MAX_PATH_NAME_LEN。 3 I0 C: ~2 j8 `2 K. Z& l c
访问文本文件的程序流程如下图:
4 Y- O* W( p8 l7 B4 q2 t6 q4 C# i5 l# Y5 V
2.2 通过ODBC数据源访问Excel表或关系型数据库表数据
% d D! Q6 d5 X9 P* [ MODBC(Open Database connectivity 开放式数据库互连)是由微软公司提出的一个用于访问数据库的统一界面标准,它提供了一个一致的应
( f; b) }0 ?6 I4 R
* g% Q5 }, _" {用程序编程接口,该接口使用一个针对数据库的驱动程序与不同的数据库协同工作。
+ \; O" @3 x6 b) f! J/ x通过ODBC访问外部数据时,需要先指定访问的数据源DSN(Data Source Name),以指定ODBC与相关的驱动程序相对应的入口。在控制面板的
0 ?( N) Q: o. b2 x6 n6 t" }. r3 X2 Y6 R9 F2 T2 U) ~) O
管理工具中可以打开ODBC数据源管理器,指定DSN。
: Q2 g: f4 f+ H( k建立MFC数据库类Cdatabse对象可以实现对外部数据的访问编程。一个CDatabase对象代表与数据源的一个连接。创建一个CDatabase对象之后
& Y" r4 b. w# V; N2 S# H8 x
H* @2 K3 g. Z4 w2 D,调用Open或OpenEx成员函数指定一个DSN,就建立起了与DSN的底层数据源的连接(打开数据库)。成员函数Close关闭数据库。CDatabase对
u7 k% {$ f p Z- q7 m/ h, d n
+ [& p D( c% b/ X% T: i! w3 A象通常与一个或多个记录集(CRecordset对象)一起使用,通过CRecordset类的各成员函数完成对数据源的读写操作。 4 D( ^9 l+ }5 ]9 |% r" j% d6 C4 C8 j
通过ODBC访问一个Excel表的编程实例代码如下:
0 b, H9 m, `0 O1 P' Istatic void do_ugopen_api(void) 0 _$ c: p7 T' a5 E
{
. E# u d( c/ RCDatabase Database; // 定义一个MFC的CDatabse数据库类对象Databse
7 F% R4 e# ?# Y& vCString SQLCommand = "select `Serial_Number`, `Outer_Diameter`, `Inner_Diameter`,`Height` from `Sheet1$`"; // SQL查询语句 8 h& \& n: X+ ]" V/ }9 G* [
DWORD dwOptions = 0;// 设置连接的建立方式
9 B) Q0 ^" Q# N5 p+ v' rCDBVariant temp;// 数据库数据通用类型 % }, M j2 w' j3 T5 y
int result; // 储存返回值的变量 8 B/ O9 I4 O7 n) i2 z' {$ I3 t
char buf[133];
- x9 [; M% h- l jtry
q/ q, \2 ] U5 d{
6 i, N- {* c# C9 E4 y# uresult = Database.OpenEx( "DSN=Standard Part", dwOptions ); // 打开数据库 7 y. M9 o, V$ `8 `# k0 L1 V
if( result != 0 ) // 如果成功打开
1 F0 z l7 i1 i4 B{ ' ]+ C; ~0 q. E& R- K6 s. ?
CRecordset rs( &Database ); // 定义记录集
+ ~1 T" y7 M9 ]; x, G' O& wif ( rs.Open( CRecordset::snapshot, SQLCommand ) != false )
* _0 _3 l' D+ e9 e& r& V' \{ & F& `! ?5 [- u$ J( r: T# T6 D
rs.MoveFirst( );
" R9 [; W L! Z, L* s( \% ]' Jshort nFields = rs.GetODBCFieldCount( );// 获取记录的字段数目 5 Y8 h/ P8 S# J6 P4 l+ H$ K- K
UF_UI_open_listing_window( ); p! x5 R. v* l4 I9 f$ a* `
while( !rs.IsEOF( ) ) # Q9 B/ x0 z* q# t: Z( e6 Y/ K: \$ I
{ 1 A' r, A* ~, ^
for( short index = 1; index < nFields; index++ ) % A0 q& q' T, M3 a; r
{
* J: G' H% ~ `2 ~( N; M# Hrs.GetFieldValue( index, temp );
1 y, C! v) q$ Q* K/ x" t! Vsprintf(buf,"%f",temp.m_dblVal );
/ S! l; H- q# CUF_UI_write_listing_window(buf ); % P8 K8 ~* S6 p7 `* [& I) {
UF_UI_write_listing_window( "\t" );
" m+ A; X8 Q8 D4 H} 4 Q3 J8 D7 U& g9 z" h
UF_UI_write_listing_window( "\n" ); * d8 T: m. Z; q) e
rs.MoveNext( ); * C4 N3 {3 I# j+ H
}
2 ~) S4 P. F- e! a8 R, j. q5 @rs.Close( );// 关闭记录集
2 V I5 u `/ b% |2 e3 ^% z$ p J} % x$ k+ i1 _ }& M" k; I
Database.Close(); // 关门数据库连接 : V! d* l# Z0 g2 B
}
& n2 v+ Q( B* `} , O1 r) X: {9 F, q* S, U, T
catch( CDBException *pe ) // 出错处理 5 ]6 C' _ y. {5 D0 L$ P
{
2 ~/ r# r5 C* Q% r! C* u# OAfxMessageBox( "Exception!" ); K4 G3 _* U) K# B' N0 Q
AfxMessageBox( pe->m_strError );
R+ P& q- w9 L" mpe -> Delete( );
% H- o) q8 G0 j8 e5 ~} & p H1 X! y1 N9 c: O' }( i
} ' N: w8 k8 A' x, f
2.3 通过ADO访问外部数据 ) M0 h( I" x; E7 v
ADO(ActiveX Data Objects)是微软的数据库对象技术,ADO里面包括连接数据库的对象,从查询语句中返回数据的记录集对象和表现数据元素
7 A- F8 N; X9 Z, N0 z& \* }# l. q2 `0 B5 f$ B9 \0 W
的字段对象。支持ADO编程的库文件是msado15.dll,它默认保存在“c:\program files\common siles\system\ado\”目录下,动态链接库1 j% a4 \) {5 }' O/ [" j* h
, p/ Y, V' v; s- ^0 h
msado15.dll封装了ADO的所有功能。在默认情况下,Visual C++不支持ADO对象。要在程序中使用ADO对象,需要使用#import命令将ADO库文件' C3 f/ M4 p+ q2 X- }+ I. @
8 ^9 I" f% g: f! X- u
导入到工程中,代码如下: 6 `) ^5 e/ `3 J: \+ e
#import “c:\Program Files\Common Files\System\ado\msado15.dll” no_namespace rename(“EOF”,”adoEOF”) rename(“BOF”,”2 B& U1 D# e# H8 ]1 H5 E C5 d
' ]% U, S' v# @7 z1 d, {adoBOF”)
2 h$ U, \# E6 Y# h: q7 h, Q参数no_namespace 表示不使用ADO的名字空间。为了避免出现常量名冲突,需要将EOF改名为adoEOF、BOF改名为adoBOF。
' ]* T7 B, X! Y; G8 T: n" dADO库包含3个基本接口,即_ConnectionPtr接口、_CommandPtr接口和_RecordsetPtr接口。它们分别对应Connection对象、Command对象和
( y0 k( ]; i7 B* X1 c0 Q2 k" Q; c3 e2 P5 N# i- [% G
Recordset对象。通过这三个基本接口可实现对数据库的访问。
& ~9 j1 O; G! y7 R4 S$ \0 H6 D通过ADO访问数据库的一般步骤如下: / x) l9 Y5 n! i6 G4 Q2 |
(1)连接到数据源; # \% q+ K' D% i: x$ G' ^( w/ _" K! _/ c
(2)指定访问数据源的命令(查询、更新、删除等操作命令);
$ b7 M [/ }1 [- Y(3)执行命令。
6 N0 U* t3 p; Y2 n1 V6 P有关ADO库基本接口的使用方法请参见相关的参考手册,下面给出通过ADO访问Access数据库表的实例程序代码段: / v# e3 b- D2 {. E! L9 g
bool DoAdoTest( void ) + S) l! V0 V* Y! y. C, X3 f& u
{ 3 g$ F3 V# p3 h; e: ?
// 初始化对COM的调用 4 ^! \; m6 |+ j( D: }
CoInitialize( 0 ); 0 V- Q5 D5 Q5 L2 |4 Z
_ConnectionPtr pConnection = NULL; // 连接
$ A7 }" Z) z( f4 O_RecordsetPtr pRecordset = NULL; // 记录集 ' C0 E8 E* _4 g5 B
HRESULT hr = E_UNEXPECTED;
: h/ @* N3 a4 X+ o6 L8 }CString strConnectionString( "Provider=Microsoft.Jet.OLEDB.4.0;Data 落Source=f:\\ug\\chapter3_4\\screw.mdb" ); // 连接字符串 5 N4 {) |$ G& h# Q0 p. X K$ [* V
CString strSqlCommandString( "SELECT * From screw_table " ); // SQL语句
" O: X" w! e6 A8 G5 M. fpConnection.CreateInstance( __uuidof( Connection ) ); // ( "ADODB.Connection" ); 3 t8 V" p0 H9 y
pRecordset.CreateInstance( __uuidof( Recordset ) ); // ( "ADODB.Recordset" );
7 S: y9 k. b% q- @* Ttry
: s; b8 h5 {, y' k. D{ hr = pConnection->Open( ( _bstr_t )strConnectionString, "", "", adModeUnknown ); // 连接数据库 , N8 Q7 \% B) g5 y; \: L
MessageBox( NULL, "连接数据库成功!", "提示", MB_OK | MB_ICONINFORMATION );
( W# V$ F0 Z. i' {$ [$ x}
6 ~% j% |% V3 o/ @2 b; O$ f: Wcatch ( _com_error e )
* Q3 K: ]+ \- |1 Y{ 3 h/ O$ Q% {- }! A
MessageBox( NULL, "连接数据库失败!", "错误", MB_OK | MB_ICONERROR ); 5 ]4 r# G o' Z& X) w' `5 T% q
return false;
$ y4 [: {& m1 r} 6 A1 `: W9 T/ w! W
try
0 Q" T& W1 {9 ?4 n9 e. v( A{ 3 I& J* d/ }% K3 j
hr = pRecordset->Open( ( _bstr_t )strSqlCommandString,
# W, e/ u. a. T" H* X_variant_t((IDispatch*)pConnection,true), $ z; @1 p( o1 r) Y% M
adOpenStatic, ! k0 ~9 A0 b" ]( Y5 Y0 @2 P7 I3 m
adLockOptimistic, + m( ^) ~1 n+ t9 D) p
adCmdText ); // 获取记录集
# x% Z) d3 w& D8 r- q" v( n- @} $ K! U0 U9 O" @* V
catch ( _com_error* e )
; X8 s0 H: h' m+ k/ ~- a9 s9 k{ 9 }2 V' V) P+ V% A+ o0 ~' y
e->ErrorMessage(); , ~4 D3 B' P+ j5 ^, c5 t, r
MessageBox( NULL, "打开记录集失败!", "错误", MB_OK | MB_ICONERROR );
4 F8 H5 f# \: [; Y* y}
1 q1 |6 v+ R1 y1 w* mCString tmp; 9 f$ p t0 F- _0 I
UF_UI_open_listing_window(); . T" K5 d4 J2 K0 k
// 输出字段名
}& }3 t# f+ ?+ ~long lFieldsCount = -1;
* m, N% N0 h, d; ulFieldsCount = pRecordset->GetFields()->Count; 2 N1 q: R9 @8 Y" I1 |' q* |( P5 {
for ( long i = 0; i < lFieldsCount; i++ )
" K/ [' R$ g" j* @6 ]2 I; ]{ & T* }/ ~0 v$ w5 x& \7 C$ {. j
tmp.Format( "%-7s", ( LPCSTR )pRecordset->GetFields()->Item[ i ]->Name );
3 w) s0 V* l! BUF_UI_write_listing_window( ( LPTSTR )( LPCSTR )tmp ); 4 {$ V: }, s8 V
UF_UI_write_listing_window( "\t" ); * h" }4 R; ]1 X" e4 h
}
' `9 L; P* `1 r' {9 DUF_UI_write_listing_window( "\n\n" ); 2 \8 F% Y6 T* t
// 输出所有记录 " S1 ^) q" E2 Q q' e
pRecordset->MoveFirst(); 2 ~. v n) z# W# s: d; @8 }
while(!pRecordset->adoEOF)
5 }; o1 v8 s5 m' ^' c) q{ $ l, e, m J2 w+ p0 o I9 Y
tmp = pRecordset->GetCollect( 0L );
+ _2 c- B0 {" l* v. C% pUF_UI_write_listing_window( ( LPTSTR )( LPCSTR )tmp );
1 E4 u& C" _" T/ R* K4 W……//输出记录中其他字段值 - J% Z4 t! s" T& l6 |
pRecordset->MoveNext();
7 q$ D3 q3 n5 i! G3 b7 |} 1 q8 z8 E C6 O; Z3 Y; Q5 a
pRecordset->Close(); 2 t% ^! f. s2 H! y" U) i1 \. I$ E
pRecordset = NULL; - g, ~4 N3 R7 ~2 z
pConnection->Close(); 8 [6 m) B$ V6 W3 P
pConnection = NULL; * z7 [7 |- Q1 n9 C# B) C
CoUninitialize(); ; @) ^" }2 P0 Q
return true;
! L, h! L7 n8 O- c" V} + N- M7 n ^" X8 I2 i
3 结论
1 J* N& D2 |! |* p+ D# A) Q在UG二次开发过程中,确定选择哪种方法访问外部数据,取决于具体的应用系统要求。通过UG/OPEN API编程较适合于对外部文本文件的访问
: N3 A0 h3 v3 y" B& L$ q; `& B, W
& W7 ?) F# J, y9 p,可方便实现用户与UG信息窗口交互等功能;通过ODBC和ADO技术可以访问各种支持的数据源,包括文本文件、Excel表及各种关系型数据库表
0 N& X- A* Y2 `' E0 s2 I1 U5 j, Q$ B
等,ADO与ODBC相比,使用更加简便,免去了繁琐的配置数据源工作,但有些数据库仅支持ODBC,不直接支持ADO数据库技术 |
|