|
ug二次开发中外部数据访问方法研究 1 前言 3 e- K, n, o# A! z; b0 [
随着UG系统的推广和普及应用,基于UG平台的二次开发工作显得越来越重要,在UG的二次开发应用系统中,经常需要与各种外部数据打交道, ( J' i3 b& o% T+ Q1 U9 k
3 n) n6 e4 W/ s O
UG/OPEN API提供了丰富的文件访问操作函数,利用这些操作函数及VC++的MFC类库,可以方便地实现外部数据读写访问编程。
9 v8 B+ w7 J% [2 外部数据访问的主要方法 $ ^ q5 N7 n8 q' ?$ w. ~
在UG二次开发应用系统中,主要访问的外部数据有文本文件、Excel表、关系型数据库表等,通常可以通过以下方法访问这些外部数据:
! `5 X0 d7 G; y3 H3 \(1)通过UG/OPEN API提供的文件操作函数访问外部数据
& ` @* f0 | m# e* k$ T$ T1 W(2)通过ODBC数据源访问外部数据 H3 R% x' i4 D5 @! C6 I! {8 g+ w
(3)通过ADO访问外部数据 % {+ K8 o, P- n$ g" P7 K
2.1 通过UG/OPEN API提供的文件操作函数访问文本文件数据
( _: Y7 j& f0 ^2 QUG/OPEN API中有关文件操作的函数包含在头文件uf_cfi.h中,通过函数uc4500可以打开二进制文件,相关的文件操作函数有uc4510、uc45117 Z( W% h% B+ W. ~9 G* X! J
) H, A" Q: O! p' e8 V* A6 e7 o9 ^、uc4512、uc4513及uc4520、uc4521、uc4522、uc4523,通过函数uc4504可以打开文本文件,相关的文件操作函数有uc4514、uc4524、uc4525: |: Y: x E& i6 }6 v# i
+ C# y8 m j# N M: N: E/ |2 M& y( }
,函数uc4540用于关闭文件,判断文件是否存在使用函数UF_CFI_ask_file_exist。
5 u* x* }1 A; h6 u! Q通过UG/OPEN API提供的文件操作函数访问外部数据时,要注意以下问题: 7 w: d A! e- F2 E2 }
(1)UG/Manager 和 IMAN中的文件和文件夹操作不能使用uf_cfi.h中函数; : j" ~3 G0 f( M: J
(2)UG/OPEN API中对文件和文件夹标识符的长度有如下限制: " M% J; C& b( m- @2 i3 v
文件名长度不能超过UF_CFI_MAX_FILE_NAME_LEN;文件夹路径的长度不能超过UF_CFI_MAX_PATH_NAME_LEN;整个文件路径的长度不能超过4 w S$ b2 x* j# h9 F) p# m) @2 `
' R% Z# Y0 R; A7 C/ D
UF_CFI_MAX_PATH_NAME_LEN。 , P; e7 s) n2 \# @3 a
访问文本文件的程序流程如下图: * G: ^/ B' \1 c/ \' J# X) {
9 z, x' o8 k) L) q$ S2.2 通过ODBC数据源访问Excel表或关系型数据库表数据 " V0 q9 n# G% ]0 N$ E( h8 X0 z+ K( U
ODBC(Open Database connectivity 开放式数据库互连)是由微软公司提出的一个用于访问数据库的统一界面标准,它提供了一个一致的应- u8 F4 U& U7 h! h5 j
2 w5 v( e/ [* y! Z1 p: m' Z
用程序编程接口,该接口使用一个针对数据库的驱动程序与不同的数据库协同工作。 & z# k) h; L2 ]8 Y$ s
通过ODBC访问外部数据时,需要先指定访问的数据源DSN(Data Source Name),以指定ODBC与相关的驱动程序相对应的入口。在控制面板的! Y' b, u) v+ n( n6 s
+ Q$ k+ Q. X5 v7 A' u& P
管理工具中可以打开ODBC数据源管理器,指定DSN。
T0 B8 E4 R# L- f3 f w3 a建立MFC数据库类Cdatabse对象可以实现对外部数据的访问编程。一个CDatabase对象代表与数据源的一个连接。创建一个CDatabase对象之后3 s5 X, P7 P9 p9 m! f
2 G% m9 j# f( H# r+ g) B' W,调用Open或OpenEx成员函数指定一个DSN,就建立起了与DSN的底层数据源的连接(打开数据库)。成员函数Close关闭数据库。CDatabase对
, n0 u& {& _/ S. M. \: g4 `. @0 ~. L0 y# x' c3 b& D& A
象通常与一个或多个记录集(CRecordset对象)一起使用,通过CRecordset类的各成员函数完成对数据源的读写操作。
6 Y) `; U C) b7 N/ H* n通过ODBC访问一个Excel表的编程实例代码如下:
# [- i+ Z8 y9 n# R0 W9 c0 Qstatic void do_ugopen_api(void) 0 e8 `- U# F0 l _) I! w+ O: B
{
1 j0 l" C% B9 T! @8 t9 O0 wCDatabase Database; // 定义一个MFC的CDatabse数据库类对象Databse
$ L& I; E3 K) Z) t- [8 m. S% S$ ^CString SQLCommand = "select `Serial_Number`, `Outer_Diameter`, `Inner_Diameter`,`Height` from `Sheet1$`"; // SQL查询语句
- H4 }- o, r3 e6 q' m. [# ^, [DWORD dwOptions = 0;// 设置连接的建立方式 7 P' v1 e# o8 w
CDBVariant temp;// 数据库数据通用类型 7 x' H6 D1 g8 T' K
int result; // 储存返回值的变量 : {* C! z# d, M; L6 o8 W' o
char buf[133];
; V p0 ^3 Y6 E: m7 t5 Mtry n! P( e" H2 P
{
1 J* X+ b. X1 h) |. ?" |4 E6 [result = Database.OpenEx( "DSN=Standard Part", dwOptions ); // 打开数据库
8 b. `8 g* l" U$ ~, }- w9 Gif( result != 0 ) // 如果成功打开
# S9 ]) V& P/ e4 J& E: J{
& f+ E+ g3 a- P; ECRecordset rs( &Database ); // 定义记录集 + f& i3 V3 [, T$ H2 l
if ( rs.Open( CRecordset::snapshot, SQLCommand ) != false ) + M2 F2 V" n" n! t2 k
{
2 b2 z+ x5 Z0 b% Ers.MoveFirst( );
! ^9 v7 R0 S1 x6 n* Zshort nFields = rs.GetODBCFieldCount( );// 获取记录的字段数目
9 ~1 u+ w2 H( w$ n) F# C- QUF_UI_open_listing_window( ); " S& v' j4 p; f. m# c
while( !rs.IsEOF( ) )
( }# _8 ^1 g" c; z5 D& |{ B+ G: u* T* m5 @% h3 ?% [
for( short index = 1; index < nFields; index++ ) " E( i; v- p) X1 p
{
5 k/ A! \1 z3 G( u4 v2 M( _rs.GetFieldValue( index, temp ); y: D8 E1 q* r, ~
sprintf(buf,"%f",temp.m_dblVal );
. j- v/ P- Y: Z: R3 MUF_UI_write_listing_window(buf );
+ L2 V) r& U$ U: tUF_UI_write_listing_window( "\t" ); 7 C& o- z; {5 @! S8 n- n
}
! }, x, y! d0 y' J, L+ {& \6 u y# [UF_UI_write_listing_window( "\n" ); $ {; H7 F# F. ~4 y
rs.MoveNext( );
: v( o# n% o5 j6 w$ u: e1 d4 c}
/ u$ d/ ?3 u) R7 \4 r9 e; \rs.Close( );// 关闭记录集
) d1 U& Z' g; R5 U& @} + ]4 [. v2 i% [' A' I
Database.Close(); // 关门数据库连接 ( C0 u1 x! a+ ?
} ) B% t7 b! F7 C3 k
}
+ C) p/ i4 m0 i9 zcatch( CDBException *pe ) // 出错处理 9 v* Z4 p9 }3 Q. o
{ + D6 k8 b, U8 u
AfxMessageBox( "Exception!" );
) @$ X' P; H; GAfxMessageBox( pe->m_strError );
! F$ Y+ S. b% q( F+ W3 |pe -> Delete( ); ( J" T( x# t5 ~
} + H' k9 T% O$ A. e' g8 _
}
* a% y! t# d; c% r. y2 J2 M3 J2.3 通过ADO访问外部数据 * H1 w: d1 [7 Y1 ?/ c, J
ADO(ActiveX Data Objects)是微软的数据库对象技术,ADO里面包括连接数据库的对象,从查询语句中返回数据的记录集对象和表现数据元素
8 G/ i( p) V( u" X
! @ H8 t: S8 ]" Z的字段对象。支持ADO编程的库文件是msado15.dll,它默认保存在“c:\program files\common siles\system\ado\”目录下,动态链接库+ I: [0 w- i. H: t$ K( C5 b
5 J: |: u& z+ M. g- Q
msado15.dll封装了ADO的所有功能。在默认情况下,Visual C++不支持ADO对象。要在程序中使用ADO对象,需要使用#import命令将ADO库文件# r# O( e' _) f9 p& P' c8 J# L
4 g7 B, e1 k: U4 {
导入到工程中,代码如下: , b6 e$ ]6 Y+ h. D- j
#import “c:\Program Files\Common Files\System\ado\msado15.dll” no_namespace rename(“EOF”,”adoEOF”) rename(“BOF”,”3 l b8 f' S6 S' x/ W6 K
1 H( J) Q: U* s0 H5 h( T3 l" padoBOF”) 9 n8 Q7 v: ^- t) n* H6 l! e, ]3 T
参数no_namespace 表示不使用ADO的名字空间。为了避免出现常量名冲突,需要将EOF改名为adoEOF、BOF改名为adoBOF。
/ n* V8 L6 I- o/ N7 @ADO库包含3个基本接口,即_ConnectionPtr接口、_CommandPtr接口和_RecordsetPtr接口。它们分别对应Connection对象、Command对象和( w$ T9 O% w' z2 Z. N
' X: A( G! m' c; Y/ C; BRecordset对象。通过这三个基本接口可实现对数据库的访问。 0 n& w3 z |, R0 G/ d
通过ADO访问数据库的一般步骤如下:
, {5 ~: D- }! m; K% b5 B) F(1)连接到数据源;
7 C8 J8 x" A7 e% r(2)指定访问数据源的命令(查询、更新、删除等操作命令); " Z5 w1 S* J. A. ~7 q
(3)执行命令。
k- G$ J( ?2 V4 z. ^6 p有关ADO库基本接口的使用方法请参见相关的参考手册,下面给出通过ADO访问Access数据库表的实例程序代码段: * ]/ I- K3 o3 M% u- c Q* P
bool DoAdoTest( void ) & f9 U, x! M6 g8 h$ H! X/ r1 D
{
3 j; E, H$ P" T L// 初始化对COM的调用 % z* s2 n% O9 Z w
CoInitialize( 0 ); % z( \0 s- z0 ^
_ConnectionPtr pConnection = NULL; // 连接
4 G3 G& z' T0 o+ O! D: e4 W0 b$ P3 I' q_RecordsetPtr pRecordset = NULL; // 记录集 $ K% U% f; x$ f. G6 a
HRESULT hr = E_UNEXPECTED;
( S3 `& X0 {( ^# x3 R/ TCString strConnectionString( "Provider=Microsoft.Jet.OLEDB.4.0;Data 落Source=f:\\ug\\chapter3_4\\screw.mdb" ); // 连接字符串 / V- D5 L# O9 G
CString strSqlCommandString( "SELECT * From screw_table " ); // SQL语句
/ ]' E3 T1 V. t1 ~) v+ x% N9 Z9 p1 ypConnection.CreateInstance( __uuidof( Connection ) ); // ( "ADODB.Connection" ); 8 p4 R4 U. Z" o# V" W. y
pRecordset.CreateInstance( __uuidof( Recordset ) ); // ( "ADODB.Recordset" ); - `- f0 W1 o4 W
try 5 l7 d$ v2 ?" b6 {
{ hr = pConnection->Open( ( _bstr_t )strConnectionString, "", "", adModeUnknown ); // 连接数据库 ( P) f+ v. g' E2 h: L) s) ?
MessageBox( NULL, "连接数据库成功!", "提示", MB_OK | MB_ICONINFORMATION );
' ]; J) s/ C9 @5 [} - ~- G# e5 l9 C: D9 n
catch ( _com_error e )
: L9 [+ u8 k& W1 ~0 G& c- N/ R{
; H4 l; _- ]- G9 U6 w9 E. `MessageBox( NULL, "连接数据库失败!", "错误", MB_OK | MB_ICONERROR );
5 a6 u* A+ X& zreturn false;
6 L, O* i1 z+ s, b$ s% @}
3 o' P! E0 {" xtry
5 }* { I% M9 l. F9 S# D$ F, s0 x( m{
$ h& o' n3 l8 T" r5 Ihr = pRecordset->Open( ( _bstr_t )strSqlCommandString,
' T' U1 s: W4 [7 b7 |+ ~9 |" V_variant_t((IDispatch*)pConnection,true), % z7 S% A/ ~/ m9 h6 z
adOpenStatic, + M0 E4 g- k' Y8 Q
adLockOptimistic, " p# d$ |% ^" R4 q$ o
adCmdText ); // 获取记录集
) I' ~+ B8 `8 `/ ?: D1 g2 V}
' x* Y2 L- Y& g7 x$ [/ N- a' _' \5 hcatch ( _com_error* e ) 2 @( N. I4 B; b, M6 M# U7 \3 _5 b, {, e
{
S/ C: I* y/ K, Qe->ErrorMessage();
' O. _# E3 K& {* QMessageBox( NULL, "打开记录集失败!", "错误", MB_OK | MB_ICONERROR ); - Z: w7 V1 o. s+ |3 }
} , t) ?* s8 w! |3 R1 o7 s9 L
CString tmp;
4 r/ Y5 z' J+ t$ aUF_UI_open_listing_window(); : X2 n+ }4 I$ f9 M
// 输出字段名 , c; ?1 @( E4 E: I$ J) k/ q7 \
long lFieldsCount = -1; * X* d2 N" v ?. n) Q, ~) L
lFieldsCount = pRecordset->GetFields()->Count;
: `( F0 h) X5 I$ l. Q- l4 Tfor ( long i = 0; i < lFieldsCount; i++ )
) u. z- `% h, i# r9 p{
7 `" V! N1 ` _3 B: S% w! `tmp.Format( "%-7s", ( LPCSTR )pRecordset->GetFields()->Item[ i ]->Name );
* C7 Z$ z5 ~2 t0 d7 ^$ AUF_UI_write_listing_window( ( LPTSTR )( LPCSTR )tmp ); / I; V* W# b- n2 @ C5 g- f
UF_UI_write_listing_window( "\t" ); , W# W: D, X: o2 o
} # j/ }7 Q, Y( j2 x1 l, ^( I
UF_UI_write_listing_window( "\n\n" );
: M8 y$ O2 j" M' W8 |1 c+ x* H; a! q// 输出所有记录
0 B8 D! i6 g, ^pRecordset->MoveFirst();
6 U8 p: {8 W T* v! s2 ?$ `7 C, Zwhile(!pRecordset->adoEOF) ! r" ]" z* c* p; M
{ 0 k& p8 b$ G/ W/ \ `: o, N, |
tmp = pRecordset->GetCollect( 0L ); 1 [& ~ k0 a4 F, i& q8 l" k
UF_UI_write_listing_window( ( LPTSTR )( LPCSTR )tmp ); 0 I& y. s6 `/ I' T, |1 a
……//输出记录中其他字段值
% Z" h: ]! R/ n7 _1 R+ @6 Q! XpRecordset->MoveNext();
8 F) v8 V" U" \! M} 2 I% j4 {: ?6 I3 k7 W
pRecordset->Close(); * P5 k6 d3 a; _+ ]; H
pRecordset = NULL;
# i' b0 ]2 b6 MpConnection->Close(); & C7 @5 ]9 O0 F b3 ~( a4 X
pConnection = NULL;
! F: T, j, q. Z8 ~CoUninitialize();
3 J% r" |9 e! u1 h, \return true;
( \: z1 F7 e4 S* i' D2 I} 4 q/ x; v1 w, I2 C+ z, v
3 结论
/ r5 U' R' C4 x$ q# S, E在UG二次开发过程中,确定选择哪种方法访问外部数据,取决于具体的应用系统要求。通过UG/OPEN API编程较适合于对外部文本文件的访问/ P8 M* t# L" P" V% d" k7 Q
6 f$ G0 ~7 b4 H! ~: C0 g# K8 x,可方便实现用户与UG信息窗口交互等功能;通过ODBC和ADO技术可以访问各种支持的数据源,包括文本文件、Excel表及各种关系型数据库表0 v& t, \' X6 u& O! _3 t7 @7 [
* H" h* l0 K2 e9 D等,ADO与ODBC相比,使用更加简便,免去了繁琐的配置数据源工作,但有些数据库仅支持ODBC,不直接支持ADO数据库技术 |
|