|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。. ~2 O. z8 m5 e0 T
7 p. H$ P0 r, |/ |
1、 用import导入ADO 的 COM 文件msado15.dll
7 y# M8 E# N9 M. M5 {9 Z {2 s8 H! T
1 l8 L. ^* P4 U+ A% n% d例如: i; _! Q2 d; x( r
! @- B2 M! s* I# A- l3 {; K #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
7 _- C/ f6 D0 b+ a( X( e X9 V) d0 L, T
no_namespace
* E( m7 H: C$ E; P: y) J- d' P. F0 b7 R! D5 N3 Q. A4 Y
3 E' }( u1 s1 G2 T+ F2、COM 使用时初始化0 \/ ?9 n1 v+ J+ k; t* n& V
6 Y& M5 y( J# q, u( l7 I& iHRESULT ComInit()+ x: d6 r: a9 S+ Z2 g6 G! |
{
1 M$ h% h+ d# j HRESULT hr = S_OK; // 默认返回值
- k! R: @) P3 v1 [6 F% l if FAILED(CoInitialize(NULL)) // COM 初始化调用
' ~! h8 J# ?8 C9 G. t% h* v/ X, Z {% o& M4 z3 ?5 K
CoUninitialize();- u0 `% q, u# ?* G. S
hr = E_UNEXPECTED;, d0 @0 F0 A- w {7 J
}
, h% H' L2 v- S1 Z+ N return hr;# c1 |( ^1 `/ B$ i- t
}! d- w: L+ P8 O* B4 J* I- c3 X* a! A
: _- v7 W# P) v6 \% \
# L4 m" }+ ^/ u% _& D3、建立数据库连接0 B* w! [! P, r A7 `
- ~# O W2 k8 l. B- a6 kHRESULT ConnectToDB( LPSTR pUserId , // 用户名
8 R" x& w) `2 X" o: u LPSTR pConnString, // 连接字串
6 m3 j1 d5 A" Y" \' } LPSTR pUserPassword , // 用户密码
0 _6 X1 j4 H$ ~( P6 |' q ConnectOptionEnum ConnectOption ) // 连接参数2 I; j1 T3 j/ R3 v
{# }$ E. H/ w+ ^; h q! q
9 ^ z# j8 R9 n8 P) V( m, o6 i! k HRESULT hr = S_OK; // 默认返回值
9 h& w8 ?- ~4 g+ {! X+ L _ConnectionPtr ptrConn; // 定义Connection对象+ e) o5 ]. z. j3 {3 `( }0 S
! w1 t9 J9 Y: y try
0 Q# C0 n% O1 k/ h9 r {
* b4 A! V1 O/ Y$ z; g! B' u+ r; _* y // 创建一个连接实体8 k+ f8 V$ u {# H5 E6 t
hr = ptrConn.CreateInstance( __uuidof(Connection) );
1 |" d) B& a3 p0 E4 J* w! P5 U% k* C" i6 L, O' L! v
// 设定连接等待的最大秒数,默认是15秒
[# G- Q: |9 o+ J# X) p ptrConn->ConnectionTimeout = 20
( B0 f5 E" z6 u) o" a; N: G' A2 O W% Y
// 打开连接
) F6 m9 j" N: g- r4 N hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
* i" O+ }6 s' D r return hr;& p/ B6 P. e3 V0 b8 @; G
}' _3 K* E5 P; D2 @- g% ]* f7 [
catch( _com_error & pComError ). p ?# N0 { M
{
. R" ]7 b( K* B+ n4 ] …… // 错误处理
; M4 P- Y; E/ A! C7 ~ k return E_UNEXPECTED;7 `; E2 {& f( P! W7 H. Q
}4 S \0 ]- S" Z% j
}
4 {0 A8 a* S$ N
' _& g2 Z9 `7 G$ k1 ?! S& @8 j* v' W$ L; f
4.执行一个SQL 查询,得到数据集(recordset) J7 j' l N D
5 t4 U2 g% y% M& s, o
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn ); M! Q; v; s2 D
{
5 }0 G# q2 f6 F( x0 h8 Z) Y try
5 M2 `+ d4 x4 h1 y# r {
: u/ q& S2 B0 V1 i M RecordsetPtr ptrRS; // recordset 对象9 w8 ~2 w' I) t: n1 S* y/ w
& i! ]3 J1 ]) _ // 创建recordset 对象实体
5 E1 O0 W/ ^) a( Z# n" z4 Q8 a% `8 r0 P ptrRS.CreateInstance( __uuidof(Recordset) );
9 j. l2 Y# ?: p# u ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, $ r1 @# K# G$ V/ z/ x1 E6 }
adLockUnspecified, adCmdText );
1 C, ` L2 \2 ~" z. I
, g3 j1 `8 p, z6 T2 o% H; h# i 或者
% S4 O& {- x j% _2 N( Z ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
5 V( Y& A; R+ y$ S3 e return ptrRS;8 j, e# X2 V8 j0 v. B
}
, x8 w0 Q, k. s. X8 d0 } catch( _com_error & a_pComError )& P3 G" V0 C3 m
{
; U5 H& ?& b& b9 W ….// 错误处理
% R7 |- T/ g( Q8 V8 C& r return NULL;4 L' S6 f) [) U9 T! I
}
; m" X- P- y' A* R, `. G2 r}
, s& d' ?- K( U( @: S
2 V* V. l" T5 w/ s! U' @& |4 W
0 S2 G; E$ s, a8 M5.通过数据集(recordset)得到列的名称
2 k# n3 |9 a' i
, O8 S8 x" E1 C& mHRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
8 e. ~* Z ? L2 V& s8 u y char strColNames[][255],
% S, r1 s/ I5 z DataTypeEnum iColTypes[] )
" t3 R. A! }- g4 c! w{6 R8 t8 n8 @2 b- z/ r
try
0 X0 a; _& `/ N/ C { // 参数变量
1 Z# R- x. s& F& @* n _variant_t l_vaIndex;! Q8 i' n" F$ l4 g8 ]1 d7 U
! n5 W1 R* N, D8 z/ |
l_vaIndex.vt = VT_I2;
9 ~7 M6 Q9 F1 J( G* {, I7 q& N2 p6 c2 S+ ]3 @: ]/ H
// COLUMNS总数
% M' G% y. t8 a6 ^' _& o& ` long lColCount;& y% P; }1 G1 F7 ?3 W
( m. I9 R, ~, i
lColCount = ptrRs ->Fields->Count;0 n6 T6 R% \- [% [
( m7 K3 J. ^, P+ C6 `: d: q // 循环取得列的属性和名称
, F+ x4 f! S/ K0 j0 E4 R1 g for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )( _% D- k4 h: m
{9 h4 W* V7 K6 `* x
l_vaIndex.iVal = iIndex; // 设置循环索引
# B- x! t4 u+ G1 a4 f# P4 @- Q* D6 Z
// 取得字段名称' I+ s/ Z+ W4 V4 l8 p4 B! P
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name); {, i7 N4 |8 i O: Y
- b5 M$ O, K" p' s+ L // 取得字段属性: T* K- h4 W$ j0 D9 t# f
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;4 O1 R# ^. P6 f! G) Y) y5 V7 m
}; l) m( j% w/ L5 k R
return S_OK;1 {+ s; _, v. v. H. x
}
- D. C9 n7 B" _3 ? catch( _com_error & a_pComError )' D8 }# e# r/ h5 ^& E
{# s% c n3 n( O6 w' n
…. // 错误处理
7 a5 x7 @. i1 ~9 H return E_UNEXPECTED;
! g: C# C1 P( p- ]0 ]9 L& O+ [ }* u% t6 J; R2 i6 i6 C6 [: C* Y
catch(...)
m. n( k% ]9 Y% X {' H/ ~9 H8 I- V2 h+ j
…. // 错误处理* m8 O0 B% A s3 P! _
return E_UNEXPECTED;
1 r. R5 R. t% ?. f! s8 k }
& W5 Y! G" G B: ^/ B4 c}% X) R) G8 V: x# G( J& B
0 x! M# P7 O! }# Q" J7 N2 B
$ B! L: U0 H0 V: {3 }- U' v: u
6.通过数据集(recordset)得到当前行记录
1 f) d5 c: W2 j/ d6 a
H4 v0 P5 C" H+ y q1 }1 h" {HRESULT getOneRecord( _RecordsetPtr ptrRs,
5 P" t) L+ o- K+ N4 c e1 [+ a1 h const long lNoOfColumns," l0 p6 {& B2 t: J3 {
_variant_t varValue[] )% k' ~; r0 C N4 }
{
/ V5 m4 M- I, Z& M4 x try
0 Y/ F$ w# D) q {
( m: j3 G1 F D( Y" {8 K // 参数变量/ H6 H+ ]0 I3 V! a
_variant_t l_vaIndex;
$ U9 W! N+ U0 O& w+ C) O1 g4 ^5 ^9 u l_vaIndex.vt = VT_I2;
* M- f/ h3 |' o8 k. \- n; G7 ^ P, c c. T7 X* ]: p) U! n# C' h
// 循环取得列的值+ U# E0 @; ?6 o3 z$ m
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )8 ?1 a+ X, G, w/ G+ k
{
4 h7 g5 n6 g s" U l_vaIndex.iVal = lIndex;7 j8 J7 q6 \4 o+ Y/ ?* M7 C+ A
, V0 _5 C+ E! F) @$ U9 t0 a& V, R- h // 取得字段值
" C% b3 c' a6 j varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
6 @, K, y) g! B2 S# s }
1 u& {1 H: }! J }, n return S_OK;
5 v! T9 n- M3 d3 d }
9 E- w/ \7 j6 { V$ s+ v% t catch( _com_error & a_pComError )
, e s5 s' \. A0 o! } {" _+ Y' i* ?2 N6 C' A4 F* [
…. // 错误处理
& W" V% G7 S8 p. ` return E_UNEXPECTED;5 X, h1 n9 y+ O$ m/ h
}
5 G: m; A! u" n) Z; E; j( D2 }" w9 Z catch(...)8 x. ^) b+ A: Z" E+ ~' d
{
, w' I3 W A9 `; v( g r7 N" h, ~ …. // 错误处理
. G! I+ S( q1 H9 K return E_UNEXPECTED;
0 w/ C( l- b& M4 `# E' D }
' J# g" _& u0 l" m) c+ p}6 S; s# j1 {0 \
( B6 k _! X! [/ i- p
+ M1 \+ A) H- v0 e6 j$ j7.出错情况下错误信息的取得$ Z5 B; y* z) a! s$ R- i2 N2 s
S! |8 R P% `% B
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );/ R! m! z7 Q/ e) c- ~# o, J
{7 S; N+ P0 J) x8 o5 s# f
// COM 错误取得
) [* j$ S: r% ^- z5 y6 D // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常3 h# U' j1 u. d! w
char lpComErrorStr512];6 c" e9 \4 w! K7 Q: f2 R
( W" T1 K1 g1 z: f, A sprintf( lpComErrorStr512,
) c9 Y# |9 ~- p7 `) ~4 \ "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",$ z' B, r$ R% U4 S, p& _; L& Y
pComError.Error(), // 错误编号
( o- Q# r' h8 l& R pComError.ErrorMessage(), // 错误信息
) ^7 h8 a+ d; i; t) z4 }# h (LPCSTR) pComError.Source(), // 错误源0 c: J- c8 u5 g" e
(LPCSTR) pComError.Description() ); // 错误描述
/ k) f1 J- v) T/ _; q+ ?0 [, o* }6 ~- _6 g5 V
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息1 F3 X7 ]5 ?. }) W/ K: E3 C
// ADO错误取得! R! D, W0 L) I1 P# |% v
1 I' m2 |4 [+ f r6 r1 g ErrorPtr pErr = NULL;
& h0 Z% i: L Z if( (ptrConn ->Errors->Count) > 0)
; ^# w' a3 H6 i l- t {
6 ^& t% b9 b M& g6 R6 l long nCount = ptrConn ->Errors->Count;
2 }! c0 p- `$ D* b& N for( long i = 0; i < nCount; i++ )8 s, V, o6 ~& m. ]4 X1 [: J: H* C
{
E" X4 T) f+ n6 k3 h1 { pErr = a_pConnPtr->Errors->GetItem(i);0 X$ j) Y w$ \" I3 ?7 c
/ Y& Y7 j z6 T" k* c8 x char l_pchErrorString[512];
' k# V& U0 E& e sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
. U6 k3 Z7 G% ~- Q% P+ V pErr->Number, // 错误编号8 B# l% X9 i, c9 }0 x( t4 E% p* t) @
pErr->Description ); // 错误描述
& Q4 F/ h% G7 j" ?! ^, G, y }3 O* m: _4 f& f* Y5 V# K
}" y$ f( F* ^$ ?
( ?6 Q F, @4 | b( n
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
7 J# @+ I( ~. \4 a& u" W# E1 X7 C3 t // connection 对象取得错误编号和错误信息。 |
|