|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。1 J% ]" n! @: V& D1 _
; A1 \9 @! U8 Z6 j
1、 用import导入ADO 的 COM 文件msado15.dll
, J* M' B) A$ o$ A$ ~! N. Z5 g- J( e0 V" ?
例如:
# z( Z5 n: z% a$ _; M' r' s; A
+ A% E; W g/ P! Z" S #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\7 @( C# ?$ I \+ w0 F' A# q
4 c% t' u( k" w7 _; @% \
no_namespace
9 c% T( Z# a% |2 ~5 Y' J5 j% w3 k. P8 J; V. L j' r' y' [. ]
9 d& T7 ]9 W6 x- v5 b \: @$ @7 J
2、COM 使用时初始化
) F3 s) {+ o3 t* u6 i; v
0 S7 ~5 `; |0 r: P8 FHRESULT ComInit()! D p8 l, e9 ^" p, O
{ " x+ H+ z' x$ `. i3 P- t" L
HRESULT hr = S_OK; // 默认返回值
# |7 W- j: p+ h% c if FAILED(CoInitialize(NULL)) // COM 初始化调用
( {. \$ e* g. Y* C! z9 L8 [ {3 w+ y9 D( D! O' ?9 _. t! L
CoUninitialize();' e I) k& P* ^: E/ c$ l4 C+ W
hr = E_UNEXPECTED;
) D) {3 W- Y& ^/ \9 x* U }( }+ k/ {/ X, T* Q/ M3 h
return hr;! o9 X, }, p, j& r1 ^
}
0 j7 p: l; {$ R" K" r9 D `( P4 T: i: x' V4 z3 D6 z" e) X# V
5 X1 @* Z! W& x( Z( M9 I* x: I9 n! l
3、建立数据库连接7 q. `. S, R: v8 A$ d% N
1 [$ {( N" j5 D
HRESULT ConnectToDB( LPSTR pUserId , // 用户名
3 m/ S& Q* m/ x! C LPSTR pConnString, // 连接字串 ; j" @4 E" ]; o/ Z
LPSTR pUserPassword , // 用户密码2 K2 N% b5 s: B( m+ W
ConnectOptionEnum ConnectOption ) // 连接参数
# Q* D( e$ c3 F4 a2 m" ?- J{
7 p" s- e4 q2 O0 _' c. D; q
: ]" h& H7 _7 q5 ?4 \ C7 z HRESULT hr = S_OK; // 默认返回值
( B5 ~- H4 k. g6 t; G8 P* R/ [/ \$ P _ConnectionPtr ptrConn; // 定义Connection对象+ }$ B- F" l, G5 n; O. Y3 T
$ r2 f5 ?# A. I8 B6 e( r$ Y try
* E, o" R. o' e {$ X4 A8 g0 l- v, s; ?3 Q3 K
// 创建一个连接实体0 P. D2 j$ ]7 x$ t- ` ?9 F1 B
hr = ptrConn.CreateInstance( __uuidof(Connection) );
: G7 @. T. Y S) m* N7 t) E# c- O/ W
// 设定连接等待的最大秒数,默认是15秒
R5 m) r: ]5 Z8 o! ]6 j0 g: B# c ptrConn->ConnectionTimeout = 20
/ j+ B F, \5 z( C! F* n! o
/ D% n1 z, k- X" S( F // 打开连接
- P- T* U" i0 Z1 x7 j4 w0 D; k hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );* T! o+ U" E' X# P
return hr;( M( ?0 a0 t8 d# y
}
- M: p; t2 X2 P catch( _com_error & pComError )
+ y$ V( n) g) p4 f% }6 Z0 e {
7 \+ Z7 K6 \ o4 \ …… // 错误处理
4 I/ Y# C. m: S1 G7 @ return E_UNEXPECTED;- P# i3 }! i' A: A i
}* R0 Y6 y6 O1 Y6 g
}3 k3 F2 C5 @% w, { h
7 c5 M1 s# w, [8 k# e! \
& v$ d# F/ B$ }5 R( Y4.执行一个SQL 查询,得到数据集(recordset)
/ a& t9 o1 t/ i4 S D1 x5 b& m( s: A$ [/ i: y& g
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )( o( s9 J) j! x8 }
{. h2 c0 C% S0 | ]
try
2 h. [3 }9 e8 P! a) z' K {8 |8 ]# i) o- d
RecordsetPtr ptrRS; // recordset 对象
e$ C& X" L. \5 o4 P' T. s3 E; j& u; w* m/ z# D8 {
// 创建recordset 对象实体
2 Z5 C- {' K# e9 e ptrRS.CreateInstance( __uuidof(Recordset) );: Y. h" K: s( T! w
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, $ P6 s0 |9 z4 y9 l
adLockUnspecified, adCmdText );" R2 ]8 d9 r9 p" u, s- l5 y% {
* o0 u m+ S7 _! c4 K8 ` 或者: ` R- _( G$ C2 K1 x
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
1 @0 w$ [4 s4 G5 H8 W( y. b: j9 Z8 N return ptrRS;
( H+ }+ t* ^2 z9 a }7 R# S/ R5 f+ L- l% }- L+ c
catch( _com_error & a_pComError )- @2 z" Q# O5 u. l4 j* L, {
{
) l6 L1 [2 P: z* N) ^ ….// 错误处理+ i3 ^: S$ F, J0 N" R
return NULL;
: G# _( c! m0 _/ p' F }
7 e- f6 k& A/ a# X}
# f. u* u/ u& m% A3 [$ @* ]9 z' R1 ?& Y4 N; ? }) C. R0 d
( Y5 _' k0 U$ I$ Z" g
5.通过数据集(recordset)得到列的名称
) q( U# e8 m4 p. Y! e9 f7 d7 l
* p. T1 h, m8 L4 [+ f3 iHRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
0 r- I1 I3 }7 o! o1 X: \! z. P" { char strColNames[][255],
+ K3 t9 D* T& B v, h$ \2 e DataTypeEnum iColTypes[] )3 R# e9 {$ a w8 \8 Z: z. o; N
{
S& y+ C2 m! N) T, P4 K try
" Y# e7 n* f& l8 ` p) ~9 P0 ^ { // 参数变量3 V/ T5 f1 R2 i3 t' h5 e5 x+ G
_variant_t l_vaIndex;
9 H5 N+ B; G' h% }( l' ?
7 D( E, r- M3 n' M% D# t' F1 X l_vaIndex.vt = VT_I2;6 F! T& M. f R3 R& w) U2 k" D
5 |/ i* A" R* a! i // COLUMNS总数. z; _8 i8 c1 N4 U; y. x
long lColCount;
6 M! K+ A0 ^6 r% y9 h, }5 q- H0 S z3 C/ ]! S7 A
lColCount = ptrRs ->Fields->Count;7 Q! s3 ?& W. a/ r
& {7 L/ h" ~8 g; ` // 循环取得列的属性和名称
/ |& Z2 G G: V8 t% m% y+ s for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )0 `- e: ^; R) Z- {
{
/ r3 E! q j( X7 |1 @1 T l_vaIndex.iVal = iIndex; // 设置循环索引6 k% l9 |* ~3 j9 e6 N9 w l: L) J
1 z" G: \3 `3 u( V0 x& Z n
// 取得字段名称! L, u2 I. t1 k4 ?! F4 {, G
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);/ u5 o& }. j y7 h% [
. E4 \" ^- V1 K0 r y" O9 o, s // 取得字段属性: V$ A1 K5 W3 {1 g6 Y+ q) k
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
+ b) Q6 V I: e% N. h* V }
! l- D/ w/ q7 z* `8 ?# V return S_OK;
1 a; h7 k7 {; Q% U* v& o9 Q }
% u# G, Z* i9 @+ t i. p% { catch( _com_error & a_pComError )1 |' g0 x y9 J0 N* d* a3 h) T
{
" `$ _9 x# z1 ~( s ?0 R5 { …. // 错误处理3 @5 `! e* p0 l- H8 `+ ~
return E_UNEXPECTED;, C- H) L! a( O& d' E
}
: P" Q ~, Y# s1 `+ v7 W catch(...)
- k1 w3 q" e& G7 o$ Z) u" q S/ O {2 X) e% u1 ?9 i( Y1 S i0 R* d
…. // 错误处理
, x8 G$ g- C I! b6 f" e return E_UNEXPECTED;6 K5 Q7 Y1 A% l) l2 q2 t9 O
}" \. v6 ~' k" H! t
}5 `5 P+ L- |7 |/ i l1 D! @- w9 M+ T
2 t6 T) u6 q% w# x# }) F% c; k
! t; G+ l$ A1 a* p+ `6.通过数据集(recordset)得到当前行记录) f& J2 I9 g( r9 Z( _, r; U& k
+ D7 M ]8 w$ g( mHRESULT getOneRecord( _RecordsetPtr ptrRs,
$ [. L1 g: T; ~' Q+ j const long lNoOfColumns,
; o( x; L% k, L* u _variant_t varValue[] )
: N2 H$ J/ S/ ]2 i O% O* ?7 j{8 ~9 B4 I, k, U- K& [
try. |5 i1 H& U4 y- F( p( c4 P
{4 I7 b+ E6 t7 t
// 参数变量5 Z; @3 F( a8 j1 N7 p
_variant_t l_vaIndex;% m% U+ E5 x" J& s8 X" p# Y
l_vaIndex.vt = VT_I2;
# l) C0 O* \3 P, o. z6 E" J- u
1 x$ `& S% Z* E3 X% _8 V // 循环取得列的值, T5 ?7 |8 N) | G i4 w
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
, w. N: Z$ } |5 u3 W. q { ) ]+ D! A& y" W7 ~) ?: E x
l_vaIndex.iVal = lIndex;
4 f: V8 B* d7 c6 c3 o
+ B: h: w1 Z0 f) V // 取得字段值% T c# J# V- u. w
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;8 J4 t, i# ?- q; _& K7 A( R, D
}! B) ~, m* R, Z J3 T0 i: \
return S_OK;
. [4 A$ }: F1 `- j: e }
x2 I) f) a4 s$ n5 o+ } catch( _com_error & a_pComError )8 S: M( J+ j- E
{) p7 D0 n2 z6 d0 s: L( R7 h) y3 ?
…. // 错误处理
7 N* V7 a( ?7 o return E_UNEXPECTED;) M1 w' M1 U$ O, ]& L8 l) ?0 m
}
+ t! L, `0 _+ T% ]3 E catch(...)
* L' \' O% R7 S. S. w- ~5 V+ [ {9 `. A. }8 b1 t. O7 d. f
…. // 错误处理6 i* t' i5 H* j* }6 D0 r( l
return E_UNEXPECTED;4 p. E( U$ x% Q& j
}
. C1 F! G. l& Y1 N" E5 N}
2 W# |! i) x6 `
. ~6 x1 A4 O1 ?7 O- v, T {2 U2 _+ ~% X4 E5 f
7.出错情况下错误信息的取得
. c3 c" o/ _ ^1 r: Y4 v4 |- I
& Z" r3 n! d. Y4 z/ M' @; T4 A2 Ovoid ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
' P, S! u* r( A' S6 R! H& |4 W{
- c! J6 r# F: f5 s // COM 错误取得, X% F, H& u7 w4 X
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常* W# Z: ?7 o' x
char lpComErrorStr512];& M( F" z" h( W i; q( J1 A
& D4 b) a4 d7 ?/ X8 f+ |, ? sprintf( lpComErrorStr512,+ f% [$ f& O/ | \9 x
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",
; d+ Q- z* P9 V9 V/ R pComError.Error(), // 错误编号
( t1 U' ^$ y% q f J4 x; J9 h pComError.ErrorMessage(), // 错误信息7 U3 D7 U# d2 K2 A) o- r) F
(LPCSTR) pComError.Source(), // 错误源
$ s+ L! S. P4 A* v6 `7 M. X (LPCSTR) pComError.Description() ); // 错误描述& p5 h" V% `% r& i* q0 w: N
- |- L$ G2 L8 V8 N' f2 b: ] // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
" I1 l# m: `6 X% b/ d // ADO错误取得 u: I" M, L$ K4 l( M! e) d: C& W
: W, x$ X. |% J
ErrorPtr pErr = NULL;
2 E4 |! O: A N8 I% I, F if( (ptrConn ->Errors->Count) > 0)" _$ y% Z) [: I7 M& r' n$ N
{
/ l4 }# I$ r& w0 C2 x# `' G long nCount = ptrConn ->Errors->Count;
7 I& H" w% V" P6 w& N for( long i = 0; i < nCount; i++ )# _" M. _$ Y: b% k4 P
{
& q2 j1 m5 f" z3 l2 C# @ pErr = a_pConnPtr->Errors->GetItem(i);' o% J1 O$ u9 ]0 m# B
4 S& Z/ ]) D- P* I6 X& g char l_pchErrorString[512];% ~+ v; O' r1 N$ r6 F* t2 S B
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",$ p. p" X" K8 d: p( A7 K- q- D
pErr->Number, // 错误编号
- M* j5 e. L( i8 v8 U; i6 M5 A pErr->Description ); // 错误描述! H; W" U! ^; E8 H! q* S: F
}' G2 W% W. X& T8 p$ O3 V+ K- S
}% i6 g) }' F K( F" f; v
) m" M3 T7 n7 E8 c // ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
$ F% U. \3 \ P // connection 对象取得错误编号和错误信息。 |
|