|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。: M, o- a! u0 Z
) k* d1 [/ e. F& ?. N- Q h6 H/ o; M% @1、 用import导入ADO 的 COM 文件msado15.dll
# P- {) J# O/ v0 y% t5 G4 p! r* o+ H8 G7 C- x+ Y
例如:
, K7 M q7 t3 a9 u o \0 \& e3 C- Y' J3 `8 G
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
, ?' N$ G. B. [0 K$ V: R) M
. C* K$ O3 g8 @- c ]( c no_namespace, i3 u3 _1 N( `' K! f3 m9 {) c
" }# y0 ^( k' J$ @& ]; {+ l3 r
" [( _8 t& n% v; R3 k; ?8 Z4 x2、COM 使用时初始化
# v/ D9 c q& _1 d. E
2 k0 K, L$ j1 r, s! b5 P8 n- U0 AHRESULT ComInit(); k; L3 k3 Z: d. ?+ _- o
{ 8 V$ P+ u0 i1 i' ]) b9 |
HRESULT hr = S_OK; // 默认返回值
. D6 T0 K5 n/ x if FAILED(CoInitialize(NULL)) // COM 初始化调用1 q5 q5 n; F/ g# C4 n8 i8 t
{
7 P) u6 e V, ^! @/ f1 y CoUninitialize();) ^0 }9 H' ~. e
hr = E_UNEXPECTED;$ C* ~, b+ y6 l3 W( a, j' k
}8 h6 ~* P& y/ a" |
return hr;4 ?; m4 t1 G8 w
}0 j- z/ Q* y; D: `; v
6 `& ?0 y+ X, A* Q9 _
; x9 J+ q0 L% ^/ T% b" ~
3、建立数据库连接
2 O" ^% @! I8 }3 u; C k. R1 @+ @+ ]" m; M" x
HRESULT ConnectToDB( LPSTR pUserId , // 用户名% b) [6 j4 J9 E* f& ?0 H% L
LPSTR pConnString, // 连接字串
7 G. d* i0 @) ~ LPSTR pUserPassword , // 用户密码8 n9 a! n( K# L) F2 _: t
ConnectOptionEnum ConnectOption ) // 连接参数
! M" {+ m% b( |# {) d. K7 N# ?{+ k4 k3 ^* J# R% x' m- [; c
3 n9 a4 R/ ^3 ?' F HRESULT hr = S_OK; // 默认返回值0 w) e/ S) y! X; c& R2 [
_ConnectionPtr ptrConn; // 定义Connection对象( E5 i0 O9 L C: L' M8 v
$ j0 I) V1 ?4 F" u8 K! l
try
1 p. K) G* Q$ V {- Z9 t7 d t- l
// 创建一个连接实体# ?6 s- h/ B/ }( q' q" w% s2 \
hr = ptrConn.CreateInstance( __uuidof(Connection) );! X9 D) u. H3 {1 E& o1 }
F* e" ~0 J9 O8 G // 设定连接等待的最大秒数,默认是15秒/ u4 s* l# z# ~. `; r/ k* O6 ]
ptrConn->ConnectionTimeout = 20
) M) J e. W/ d' J7 ]0 W7 e' r0 `4 O/ T$ H
// 打开连接+ }. a& ]5 F% G* |/ U) N. d( h
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
* x8 t# J7 B. N: {4 z J) q return hr;# Z( f- q$ |1 i d
}
7 X9 H/ D/ E1 U, k catch( _com_error & pComError )
( S. _' H4 R2 p/ k' z0 C1 N0 ]) p {0 [: P6 \' o$ L" e2 t9 C
…… // 错误处理& J! ]7 E, [2 `( R
return E_UNEXPECTED;
; w p! d4 Z) t# J }0 d2 M" I5 W- ~8 }6 M6 {
}
6 C3 w/ n3 e$ F9 q L) ^' J: y6 {( [" k! L5 e% k$ N
. w, G) q. B' P( d8 ]; e4.执行一个SQL 查询,得到数据集(recordset)
_, P, T1 j/ e2 u5 N: k- C9 h$ S* m
; i3 s4 I& ` F, M! ^_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )# d9 o% T0 ], v: x/ h
{7 a3 Q" f% }0 q( {
try" m$ J& w( X7 r
{
# @( I; V/ t. ^8 Q; F, ]6 G% l' Z RecordsetPtr ptrRS; // recordset 对象/ m3 e6 b& b z1 m' Q6 c
$ i9 \# E, O+ i. \% e6 S9 I) c& p* }/ S
// 创建recordset 对象实体' G5 j3 U+ K. H+ h; N7 G
ptrRS.CreateInstance( __uuidof(Recordset) );: t& M+ p0 ^: Y( j1 M: i4 M: ?
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
8 w6 w8 C4 y/ y7 U! i8 D9 S, `adLockUnspecified, adCmdText );
. Y! N) L( Y$ O. X$ o( o
! k& c, ~: K+ Q 或者
* a% W0 E! K X6 P! R1 Z/ r ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );8 {1 P0 E# @, I2 f& `6 E4 `% N0 T5 l
return ptrRS;
/ [& A- X% A2 ~! U }* X, Y: `" L6 D
catch( _com_error & a_pComError )+ r- j0 k7 R( L4 ~+ W0 \
{0 c* M8 F, @4 F! k
….// 错误处理, G6 y* ?; C+ B* y$ p' X6 C5 a
return NULL;
$ M0 t5 }$ S0 e' L7 O; K: g7 N }
. |0 c1 x/ y6 | _1 L* J3 w, _} U1 @3 z4 ]6 W+ w1 ~6 m f% H
9 g% j( X& s# g X8 W( q
& q/ v/ R% T1 U- t( X) B5.通过数据集(recordset)得到列的名称
" Q f4 p6 U, J: A
6 T5 X/ X5 ^- \ t5 zHRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象) ?7 t3 S" Q+ N( p% ~+ {# q2 P0 u
char strColNames[][255],$ B9 R* I; D7 M: _
DataTypeEnum iColTypes[] )$ Q: y/ G( X$ w' z4 c* w! c
{
, E# a ^6 a1 ]: d try
# m$ P$ r& L( J8 b& d3 G) W- q* o { // 参数变量
, ]. q% w5 [( Z) E" _$ r _variant_t l_vaIndex;
4 v+ J) [ R) B; R8 ?% k I3 d/ q7 K2 m; J6 [# L3 b# x8 \
l_vaIndex.vt = VT_I2;
- b# o/ `' D/ a. M. A
* ~8 X! x0 K% w0 l // COLUMNS总数+ z9 \$ y) s. d) F+ N' z
long lColCount;
. H2 r9 d1 W$ k3 ^$ u* U- A: e; X) d" o% q5 `! k
lColCount = ptrRs ->Fields->Count;7 |6 r) a9 B6 R6 D
1 m3 K5 N& W5 t7 n // 循环取得列的属性和名称# [( J, h! v4 V! [ f1 {
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )6 T4 K, T' g2 E1 n4 c
{8 w$ k% U) V" K v
l_vaIndex.iVal = iIndex; // 设置循环索引
) ~- \* f7 n7 q* \6 c7 i+ I4 a' K
# G9 n$ N) {2 H! W$ j // 取得字段名称
# s7 m( X6 W% }/ f sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);0 i6 d* F4 N* W/ S
' s' r+ A) q2 h2 }/ n+ q7 X
// 取得字段属性
' I+ \: a) v5 B: U* N6 k iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;. a9 X7 m* @' Y2 Q6 a
}
5 e( ]: E+ Y8 \+ O* o7 B1 b; Y return S_OK;0 ?( y2 b$ j: ]5 X. @/ o T
}
6 w6 R9 U; V4 a0 Q# F9 o catch( _com_error & a_pComError ), H& R+ P( y9 b3 [ s! C
{
( E+ u, [6 ]9 t …. // 错误处理
b4 j0 ^+ B/ N+ ?4 S# A5 Z return E_UNEXPECTED;% {' y+ |2 C3 Y' G9 P$ m
}
7 m8 y) D! T5 o) U) H catch(...)
# ^/ ]( W j9 z G" Q1 M# a0 p {
& ]% R- V8 h5 @: j: ?7 z …. // 错误处理
( w7 p6 A7 Y+ ?# I2 m" _ return E_UNEXPECTED;
0 o4 w G9 H$ v/ [ b }! R7 a5 T' y. W* ]; u
}
; W5 T' K: D/ J _" }8 d
9 i: m6 _6 X! B0 F, z& s" J* ^' L
6 h) ^8 F$ V7 t" d" `# T) L+ h6.通过数据集(recordset)得到当前行记录: G5 o2 I$ t4 y: b
g# E) s0 x0 K' r, l$ `
HRESULT getOneRecord( _RecordsetPtr ptrRs,
) |' O( r( U- r* m const long lNoOfColumns,
) e0 h! x4 _" _. i0 V6 V _variant_t varValue[] )4 f. N0 |$ O: h& p
{
Q2 V+ s% l. f M7 Y5 b4 }* B try8 D9 M$ K2 I' D, |2 t
{2 m. S) W4 |8 @! f. T
// 参数变量
' W% I* u2 V. I3 c/ B _variant_t l_vaIndex;
/ T+ ]$ ~' x4 ^( o5 G' I( D l_vaIndex.vt = VT_I2;6 [5 g( j9 ?( I3 K
& o! H& R3 ^4 |3 @$ u* P) }7 ~ // 循环取得列的值
1 p6 Q8 m) v- {6 n/ {, s1 ^+ E3 k for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )2 K) g' N$ _/ Z
{ / I2 A- ]3 H+ A, B, a- }: N
l_vaIndex.iVal = lIndex;$ m" e( l) h4 R( f" V7 ]& \
- d$ t, h1 F& J/ t, S; L+ b: m5 C // 取得字段值; t7 @0 W7 {3 u) X3 C. L; }- b8 Z( F
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
7 e3 ]$ m/ W8 I1 e4 j+ B# c9 G }. C6 F/ y9 S/ A Z L1 R
return S_OK;2 C z7 C. v6 n1 m+ x3 ^5 x
}
' f3 v( \3 \: G' G) q7 y c! F catch( _com_error & a_pComError )" Q. H, \- H- ~" a1 |+ M# k& v
{3 R6 ?. i9 Q0 Y
…. // 错误处理
$ S7 S1 u/ w/ ?+ `- |: X# B return E_UNEXPECTED;
# T5 t9 ]. R# W; }3 K1 {) o& D& ] }
) T: U8 N4 L. E catch(...)1 j! j; h; u: Q( {% K; \4 O
{
" ]4 c8 L, i6 G4 R, K' { …. // 错误处理9 s0 T/ @* u! e& L! c3 G
return E_UNEXPECTED;
' U2 y1 X+ z8 i }
! n& d; u- p6 I5 d}
6 t2 ]; a2 ^4 U3 e
+ J9 Y2 F; B% X! i$ E1 B- f6 v9 E6 {% o# R; M) _
7.出错情况下错误信息的取得0 t4 K$ J3 a: K3 X7 ]1 A6 k3 G' K
; d1 ~" l- E3 i3 c! K
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
) t5 q7 G1 F9 Y5 O{! B, ?2 R4 b- S! t
// COM 错误取得4 Y }1 _8 v7 k9 A) w3 y
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
7 l9 _* F/ A3 v7 B char lpComErrorStr512];
# P' i/ ^ P2 ^4 K$ s- r- r% P/ V
1 z3 h; X" c4 e& ?0 {) L; v* ] sprintf( lpComErrorStr512,) ~% ^2 e7 o' B( p, L
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",! w, Q+ |) U5 U! G
pComError.Error(), // 错误编号
7 e: E% M& [! z pComError.ErrorMessage(), // 错误信息# Z7 U& o# P% O I" I0 g2 ?: }
(LPCSTR) pComError.Source(), // 错误源9 [. U' z% A8 f Q
(LPCSTR) pComError.Description() ); // 错误描述
/ w$ H# {" o9 B1 g
8 V# [3 L* d3 o3 s# C2 c* h* Q5 I // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息$ r0 {- t, @6 ]4 C7 b1 y
// ADO错误取得
1 ], k: S7 r) o k+ X) [
5 O' l* J: S# R. ~5 p# n- |% u ErrorPtr pErr = NULL;8 G; u: S0 u9 O* N# s6 k' c+ @4 E
if( (ptrConn ->Errors->Count) > 0)
6 E8 P; r& u" r# d! n( | {
5 c0 f1 b# {( \ O" Y long nCount = ptrConn ->Errors->Count;0 Q, l1 G5 J6 q. b3 a
for( long i = 0; i < nCount; i++ )4 I8 _ f7 Z! ^- G5 n3 ^
{
7 \ q* E5 ?: l& ^6 K pErr = a_pConnPtr->Errors->GetItem(i);
& M8 p" w$ ~8 g2 \' ~8 ]2 x- K# R: [/ |: l
char l_pchErrorString[512];' r# k# M$ H( \; P0 H8 e$ R: k
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
4 M9 ]0 j8 m* V pErr->Number, // 错误编号
$ t6 \8 s+ C4 R$ @% |, f pErr->Description ); // 错误描述
" O; U1 r. j$ l6 ~, N- y1 e5 _ }) c; O! _- ]8 F$ J2 y
}
( @. `5 b& o7 Y
2 v# W- _8 i. r: x3 a // ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
6 t9 d% b3 {7 @# p. b% X' V // connection 对象取得错误编号和错误信息。 |
|