|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。& o* ?) r3 X3 P9 }
% t/ }1 A7 h/ L7 y9 ^) A. O1 N8 R% r q
1、 用import导入ADO 的 COM 文件msado15.dll
+ H5 l1 T+ O2 w/ m; @0 {% k) D2 a) C$ }/ ]
例如:7 M. q$ y9 e, ]
1 w( K' q# S5 ?+ D #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\/ p8 A, ~/ s. |6 W4 L
1 y8 P7 }5 ]# m$ x4 t7 Y: h& Z! G
no_namespace4 W/ g) [' Y3 H' {# |
) l( {- L1 ]; O3 g0 f( j
( x3 E1 v/ _/ c f8 r: S2、COM 使用时初始化3 q8 K/ \" T, n6 z& @" m# e0 J, z6 h
: }& {: y, k) v
HRESULT ComInit()1 R8 \. k+ d5 z8 x3 z1 v5 [* A
{ ' L! A9 u3 P3 x: j
HRESULT hr = S_OK; // 默认返回值
9 J6 H* T3 V: A; p, W; G if FAILED(CoInitialize(NULL)) // COM 初始化调用
9 g+ l4 g r( v( U9 V$ Q$ {. } {
( D+ X/ w2 ?6 H/ d6 o6 z. l# z. E CoUninitialize();
# S( ?7 h* v9 I0 o hr = E_UNEXPECTED;
! G) @/ O1 N5 E; ?: C }" X, K8 B' G5 G3 Y$ e- g
return hr;
0 d& h0 T+ L/ K. {; j, O! ?}
; ~% ]7 ~7 y+ c
x4 |4 s9 \# l: ~
- Q4 `) y& b2 J; A3、建立数据库连接
}+ s9 `5 h7 l ~# q
# G3 f) x$ }$ o! Y4 H! q, b1 CHRESULT ConnectToDB( LPSTR pUserId , // 用户名
0 S# ?4 m. z% e; l, q- J5 t LPSTR pConnString, // 连接字串
b1 n, k+ L6 y LPSTR pUserPassword , // 用户密码% U$ E- v5 E6 y: \2 r6 l
ConnectOptionEnum ConnectOption ) // 连接参数/ R5 n# A, ^& | ?! \
{. n7 f2 ~) J3 N7 f4 j# D& [
4 U+ V/ n1 [2 t7 a5 M5 ?' W/ p HRESULT hr = S_OK; // 默认返回值6 l# P; {5 l) Q9 Y" p. A- N) r
_ConnectionPtr ptrConn; // 定义Connection对象
' g) S6 s" ]7 W
; h0 b0 x) p0 F' q4 {2 u try
) u% l2 ^5 x! v( T) i5 g {
, ~1 v* y- N' j2 `7 f+ S2 i( m. Q# b; H // 创建一个连接实体$ `" F4 ?7 f. ~( ~4 R
hr = ptrConn.CreateInstance( __uuidof(Connection) );
% H8 O2 S" e- g4 V! \4 ~, H4 a: S5 ^
// 设定连接等待的最大秒数,默认是15秒! r {3 {+ h8 m* Y- @8 H- \ d; Y
ptrConn->ConnectionTimeout = 201 h2 i3 ]. E& o$ N" t0 T% n
. ], U: p) u: X' p {4 T2 @; |3 O
// 打开连接
' x5 ~! E- O3 `1 t6 o" n/ l' _) K hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );) `" r$ N& {! `% l0 M, s6 Q1 \
return hr;# ]8 U0 Y* J4 }9 q2 _% {& O3 \
}. `1 \) `# c* I# Y
catch( _com_error & pComError )
! W# v) J$ p! }% h* W0 D {
7 z% B. `) L! f" F: S' t4 ] …… // 错误处理+ l, I; C# O! L y, T2 s1 U2 d1 d
return E_UNEXPECTED;% T, D& Q3 w/ a
}- |4 t7 y& }/ |
}
3 }6 O/ ?+ n' F" c$ Z. @6 L3 p- x
$ _% p# q7 H9 P D5 b' E: ]% j$ M! b. q$ F
4.执行一个SQL 查询,得到数据集(recordset)
$ g$ {- i7 J5 [7 _
0 y( s& @0 F! }9 h_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
3 G8 }4 r1 G5 N9 q* Q5 ?{
3 W: Q7 V* `# Z. t3 Q2 v try
& K R. R# j) o6 ]- s+ s {3 q8 b* f. `8 F
RecordsetPtr ptrRS; // recordset 对象
4 [7 ?! d! {' }) ^0 B" h# e2 j, Y( C2 w
// 创建recordset 对象实体
0 _, _' [1 A$ a) \6 W" w ptrRS.CreateInstance( __uuidof(Recordset) );
9 Q _0 |; K, ^5 s ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
% n" F. |$ ~7 L- x& R1 @, C* {adLockUnspecified, adCmdText );, f: @6 L! G( ]# l
1 E0 n7 }- ]3 ^) L
或者" E4 K& D; d( q4 E
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
- W. S! v) J4 m$ E return ptrRS;
' v1 P9 W5 s+ L+ G7 g }
& p$ k. i% b4 _& H6 \% m$ _ catch( _com_error & a_pComError )
& l+ j. y* P* C/ b; B {
, _) p! M% N& x( d& N$ }. L; V ….// 错误处理
8 b% C" b- }& c7 m return NULL;: S3 C# [, f e, b& e1 ?2 Y. i
}1 M( o! e0 a" `, K! K) v
}
1 e( F; T- w+ U- C6 g& d# }. E7 p; v# m4 i5 H, T3 k
' t. r7 k/ u% G! M& p
5.通过数据集(recordset)得到列的名称9 `) ^+ G7 A- C( ~: c4 c7 P
4 e& ~- i b+ \4 zHRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
" K: R/ e; k7 ^& e; @ char strColNames[][255],9 J9 n# _! ]4 ~4 F% R0 P' d
DataTypeEnum iColTypes[] )3 b h# I9 ]; X9 a( ~7 n: p2 t
{& s2 F$ a/ A% w7 _
try
& k3 @' J2 s" D( i( m7 ^ { // 参数变量! e3 v6 r/ D9 Z+ S6 X
_variant_t l_vaIndex;
! E4 t% W& q7 q$ b9 l+ \3 c5 W" k6 P/ S6 w$ w
l_vaIndex.vt = VT_I2;
5 d3 F& ]" p8 q+ ~+ k5 P2 d4 o h }; C& t# w
// COLUMNS总数
: ?! {6 w: I; B long lColCount;- M; i- _7 t: U( X# b4 u0 ~& {
1 B e) I% O9 Q6 u' D4 o lColCount = ptrRs ->Fields->Count;
0 u1 J- f3 t" f. y9 S' S4 ?, L" L3 w4 w" K% X) L0 J
// 循环取得列的属性和名称5 G2 n8 \& o7 Z. i
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
6 G; R# q7 H9 b) w8 p' ]: I! z" y {
% ?$ t2 Q2 c! ?9 [ l_vaIndex.iVal = iIndex; // 设置循环索引
! t% F( D1 K3 z9 W3 n! u* W4 W: P+ p* L6 g% N0 V# c3 x) V
// 取得字段名称" Q- Y! c* C- \8 @/ |0 f/ f2 Q/ O
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);' }" r# Q( i9 `# n
& M, v( W8 W/ B9 |( W' X, L
// 取得字段属性8 `# S( p4 ?: k, d% s/ E) i3 N9 D
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;9 R9 t6 P: t- W; a8 c/ K
}# M6 O. A O8 ]4 g
return S_OK;0 B7 G7 J4 L/ C( U$ n
}
6 R! u$ E7 g6 l* e* ? catch( _com_error & a_pComError ); I8 [. C$ i) f. c' |) W/ v( t
{& M) B' {3 C% N# z+ a- f
…. // 错误处理! P" Q: B, z+ ?- Y A
return E_UNEXPECTED;
& f H5 Y3 Y6 Q) G5 O( } }
. _# Z$ p# @( _3 O/ }( W3 C6 i catch(...)
2 p* k6 [3 X9 B; u: M) Y {; k+ N; v8 E: l6 K+ m$ z4 ]
…. // 错误处理
! V% L) j8 [6 |( y! |& {1 n return E_UNEXPECTED;: _' t, B- h" Y0 @4 ]' a. ?" m
}
% [/ I6 a4 X0 C+ i}( @# f }( O9 f b3 w; i1 @
* G5 Y' L! g8 @: w" n# @. a3 ~) f+ ?0 K+ R. x* G5 g; C
6.通过数据集(recordset)得到当前行记录' j* t' y) g& f8 S( [
6 i4 E2 d: @/ D( |7 Q
HRESULT getOneRecord( _RecordsetPtr ptrRs,+ N6 d! V6 F5 C$ M
const long lNoOfColumns,
! f& ^8 F! Q/ [ _variant_t varValue[] )
: w/ X7 {" t7 @7 W% c9 L7 S: x/ i) ]/ U{
/ W* u# T/ G9 N% Z. ` try5 _3 P% ?# }5 F2 b+ I, \/ h
{) v0 f; J& M1 q7 b6 Z
// 参数变量' u0 R8 k2 l, }
_variant_t l_vaIndex;( {% C7 u; C) l
l_vaIndex.vt = VT_I2; T- N5 E9 p. k. t+ J% C+ E
4 ?, K8 ?0 w; d! l
// 循环取得列的值. r |5 }8 H: d8 H" C; n3 Q" U0 C
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
1 j8 d% w" _9 @# x4 D {
, J3 h4 |9 k& Y2 t5 W& Q F l_vaIndex.iVal = lIndex;
& N, N, f0 k7 g) I8 ] p1 V3 ^% \4 o% c2 v5 T. ?5 R
// 取得字段值
3 |! s `7 ~8 [+ _ i4 x$ M varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
/ K3 B% T( ], T$ `9 M: e }
) d( {5 V5 J( O. u2 | return S_OK;
2 H* L1 x" ]) G$ |) s% f5 R: [. B }) P# |% V+ I, ^. z3 j" ]
catch( _com_error & a_pComError )2 C7 w; X' n) E" X6 _9 l, S
{
: `1 q& W# d/ W* w …. // 错误处理" L7 @# Q( f4 l8 }
return E_UNEXPECTED;
& Q# X* K. W4 b1 I }
6 `2 v9 {3 h6 u" e3 U catch(...)
0 S0 Z5 c/ k: @- F! I {
2 B4 S {: G1 x2 {, i% F …. // 错误处理5 b9 D+ }: ^7 o. Z- N2 A3 \' I
return E_UNEXPECTED;, ~5 q2 G: _. d
}
0 e) h E9 N; a' B}2 O. }2 x/ |1 Z5 O% g( e$ @/ e! b; r
! F/ x$ V( d2 j. J! _5 U. E$ x2 v6 L
7.出错情况下错误信息的取得
( U5 v7 \5 l) V: P. A) @- v
1 j8 P; Z2 v6 B4 ]void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
7 q9 e8 H* q, ~7 h: d- T' f5 s z5 ^5 r{1 a8 w; j: k6 [) ~0 D" U
// COM 错误取得
G. h5 M) \+ U4 u. Z+ y# X J // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常5 W8 T' o$ x4 w, M/ n% T
char lpComErrorStr512];( H- T8 F" K D" {, v: D% h
1 k2 V1 @& s4 i* a9 C
sprintf( lpComErrorStr512,+ ~* f: {' p3 n5 I! Y- A$ K8 @
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",
& b3 ]5 B) L& ? pComError.Error(), // 错误编号+ b' }2 p0 H6 g% y
pComError.ErrorMessage(), // 错误信息
5 D1 \3 L, V% d: N (LPCSTR) pComError.Source(), // 错误源' G, a+ E& E1 Z0 N5 T% }
(LPCSTR) pComError.Description() ); // 错误描述
* W7 Y, f* v& T4 \: m) g- R
6 ?7 F5 z, \' c. f' R% `' o+ Z/ o // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
0 l+ g+ g. d- S/ t( {( u // ADO错误取得% R% ?2 F* ~- N% ~! @
/ t5 M) R. T0 j( @ N8 J" d ErrorPtr pErr = NULL;) y5 W- E5 {$ O$ s0 `
if( (ptrConn ->Errors->Count) > 0)
4 P. \5 A6 g' C! {6 t* a {
% n" t0 J: w4 z* Q0 Y long nCount = ptrConn ->Errors->Count;
0 F% e o5 ]2 a for( long i = 0; i < nCount; i++ )
) ]% c+ {2 S6 x' N. U/ Y/ f. ` {( P; e6 [9 |1 b& H% i% L
pErr = a_pConnPtr->Errors->GetItem(i);
+ c1 i& [9 O i. \% G) Y$ S: x0 @
: x c: q& W4 H3 f char l_pchErrorString[512];
% g! D: s! f& }7 L% q/ a' g sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
* Q' d1 G( N3 L+ W' m) h pErr->Number, // 错误编号
$ C# `' Q M* Z9 Q- h y( i/ S pErr->Description ); // 错误描述" r1 y4 l. O, {7 H" D' K d' i
}, z# E3 U* B! s% ]4 p2 ~) ]* L- E
}* `; B& |& l2 t- K' _7 F
% W1 d, t, ?& K/ M# c4 `% c // ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问2 p; d. O' h0 e; p! I( D$ U
// connection 对象取得错误编号和错误信息。 |
|