|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。9 P/ x; Z* }$ y" Z, u2 J: F
% |7 A& h0 _& r
1、 用import导入ADO 的 COM 文件msado15.dll4 s5 W! C% W5 h0 R
) G7 Z' j9 K, |
例如:& z# e- N) r+ k: K: ?/ E. n
) Q) b+ m8 t+ m! a. M
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
* t4 J7 ]. O- ?% x1 j; N. ~3 X. `4 M/ f# E0 R* }$ \2 [2 ]
no_namespace
9 i- a( W/ K& k F$ n3 u: j4 \+ I3 v* c# X+ v
) u0 F+ F% u! S* y
2、COM 使用时初始化
9 \1 C( H7 J, P N* b6 M% j8 m* k0 ^( v
HRESULT ComInit()# q2 [& t1 V% e( k5 w/ l* |
{ $ ?& C1 q, d' S
HRESULT hr = S_OK; // 默认返回值
/ X, I) F2 K% s, h if FAILED(CoInitialize(NULL)) // COM 初始化调用" l/ R& D' `' E# C7 V. Z
{; L( M. h4 n& T4 `0 e b
CoUninitialize();& x( i( w* z. u" {3 l
hr = E_UNEXPECTED;. @/ o) y8 ^/ B
}
& p! r- S: E+ e return hr;5 U3 O5 |' ~9 s) h5 ` ?$ }) p! ~
}) H9 B* A& T' B9 N
( ?; L3 A' g( P/ X- O0 l, V6 l( n3 m( @ W \8 ?
3、建立数据库连接
9 v l2 Z0 d' U$ }6 F2 j/ Q7 Q3 D
' s& Z' n3 m; U# w6 M" AHRESULT ConnectToDB( LPSTR pUserId , // 用户名
& o" |1 m* B- m$ m* Y, c) t LPSTR pConnString, // 连接字串 # \% W% ^( Q0 C$ b I# P. C0 \- s
LPSTR pUserPassword , // 用户密码
6 i! F3 S4 A' O, Z4 F7 @8 U7 P ConnectOptionEnum ConnectOption ) // 连接参数
( G4 [$ z+ Z$ ^8 {' _' @4 K! R6 Y3 {{" V7 O- [* ~, w9 ?/ h% O$ c/ v
" { X. d1 e5 q& p) p2 C7 `! }
HRESULT hr = S_OK; // 默认返回值
, n$ ], k: C, [" f% S _ConnectionPtr ptrConn; // 定义Connection对象
; Q) v7 j: S/ O! Y0 F3 G+ v/ D
7 R' x0 U9 X+ w8 g9 S0 J try, g. a2 j- ]9 e; v( V' }5 h+ K4 A
{0 n' P8 z) p" S
// 创建一个连接实体
# M6 c/ P4 j7 P/ R! S5 N hr = ptrConn.CreateInstance( __uuidof(Connection) );
& ~# S' C; p8 K) o7 z: f! x; ^: ?( t& O+ r3 `, ]( ], o+ U% R. G( X
// 设定连接等待的最大秒数,默认是15秒. u" O4 Z+ @, b+ D* f
ptrConn->ConnectionTimeout = 20
( J% f8 N( H4 p' G' m2 r' q% s* l! g7 l6 \2 x" T
// 打开连接; t* C6 D1 [, w$ N
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );) V+ @) X: H' S+ j; g' F- I
return hr;
, w. J; ]6 Y: b2 ~& O" a. [ }
+ R$ I4 w4 w- W catch( _com_error & pComError )
4 @, V( D* i/ h: t5 d; w {6 I# }- N1 R2 m; ~8 c9 V
…… // 错误处理
* {1 G9 i0 I; k return E_UNEXPECTED;
: ~9 f( ?: v9 ]1 H" t }+ n- E/ M q' h0 h$ g, @
}6 ?+ A! L! c, r0 H
! L( L" }/ y" K. _
( l0 K1 g3 ]) C" T1 c: R4.执行一个SQL 查询,得到数据集(recordset)
0 f& f& d- U# G
5 R' w0 Y$ }, _1 V, X8 C, T! r_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
, V8 o0 a; d. `+ f{7 b f( @! U6 k. I- H/ L7 A
try
K2 [4 y0 N3 I9 x: ~! i" Q5 E {
# C6 R$ o8 j# L% | RecordsetPtr ptrRS; // recordset 对象, F K: I* S, Q, W8 v3 ?
$ M# c% D. s. G1 z b" e! C8 Z
// 创建recordset 对象实体
: X3 U) ?1 }6 D( V ptrRS.CreateInstance( __uuidof(Recordset) );
7 K5 `8 F( b/ } ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, + G8 k% |: t0 L
adLockUnspecified, adCmdText );
. X$ k% M/ r. n, t7 n: |& Z8 U+ _8 p5 R* J9 X
或者( u3 w* ?/ {0 y1 D2 U# m
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );+ Y4 }% A4 L) U. ?, I* y
return ptrRS;8 i- {: O& A- ]0 i* ^+ Q
}
3 y2 w: z5 ^: F catch( _com_error & a_pComError )
3 p) C. ]! |0 B& B: \* z8 i! p {
& i; T) B5 j( x- J3 e, V5 X ….// 错误处理
' F5 l' E8 k$ y, ~+ A$ v return NULL;
4 Q/ P4 g4 l; F8 P0 ` }
2 S0 N9 e* g1 }( d* B: i}& R9 }8 {% L% F5 K$ g
( m H S" J) d9 X: e
$ o" G+ m5 ^% k( S! r- ?7 [# X5.通过数据集(recordset)得到列的名称
0 V$ P, F& g7 ^( ^+ O( V& P% ?# J3 v/ `
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
; J% N9 H! l+ h; n+ h char strColNames[][255],
! Z) s8 g$ o" d$ B( e7 w DataTypeEnum iColTypes[] )% a9 Y& r Y8 }, U& Z* N# x8 r, D
{# @6 E4 D2 j5 Y. \/ v
try" P5 W5 I: u& d+ l
{ // 参数变量
8 t) u6 u9 r, u, k3 S _variant_t l_vaIndex;( v7 {6 L M' ]; F4 n$ ]+ a* `
' A$ p9 k% e2 j l_vaIndex.vt = VT_I2;
$ ]7 H1 b! h( s( J/ L9 _
4 n2 F& ]! f: I- p // COLUMNS总数1 m, i8 S+ _% [" |2 o5 ~
long lColCount;
$ t/ }+ r6 Z6 ~% z, e
$ ^3 s- w& ]) [' o. `1 C lColCount = ptrRs ->Fields->Count;' z$ q( t" w; O: T
. r0 ~1 y% P3 Q4 d2 @ // 循环取得列的属性和名称
2 q) t( k2 |9 T' h* E8 F3 g- b for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
- j& ^0 h% P1 j5 _ {
$ i& E1 B) i) K1 T! n4 ]* k8 Q l_vaIndex.iVal = iIndex; // 设置循环索引" t& R/ `( D$ U& [: X% |
* D. h3 z# g3 ~$ M0 Y# x& b // 取得字段名称+ I3 k$ E, ?% y& M6 b2 c% ~0 X
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
4 x9 W+ r0 ^% M0 I' y- v, U6 N8 F
// 取得字段属性
3 s) a5 {. i( I& d4 ^/ p; n3 E% ?( g iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
5 g/ y% J" O) X; J) ` }
2 d# f, k9 F7 M return S_OK; Q# u( ] t! @& V
}
6 L0 W% c4 L# H catch( _com_error & a_pComError )
8 s& O2 [# h. L8 | {7 j N9 Z6 X, v' g) h8 O: U5 X
…. // 错误处理% i9 X5 |) n/ A! ^
return E_UNEXPECTED;; u+ f4 ?6 N4 c4 {3 Y
}
: u; `& f( C) D$ O, G+ _ catch(...)& o+ t( r V7 t) t9 ?7 ?
{# k6 M# D! y$ T! D6 `& i4 T) D+ I
…. // 错误处理
/ M+ |6 ]8 H* Z* x: u8 V return E_UNEXPECTED;! s2 G3 L& c- j0 G3 J8 X
}" {' E0 k6 u/ v/ z
}
/ F4 E, @( |8 G. _8 H" |. D' m0 w/ k
: j* H5 e- J+ _: j* g9 C/ K6.通过数据集(recordset)得到当前行记录
9 k' t& O: O6 O* l5 \
5 L: a7 ^$ W$ @) ZHRESULT getOneRecord( _RecordsetPtr ptrRs,$ i/ k: E& i/ V6 | w$ w( E/ N
const long lNoOfColumns,) H, U& m) s8 T3 X, d, }' k ~
_variant_t varValue[] )6 f5 o. T1 Y2 D+ L# M1 E! }. O
{
6 Z |/ `- k m U try' ^" S: j- V) D; _- x5 i) b
{
; m+ x; d0 K7 ~# ^ // 参数变量
, f; R. }; r, g1 a _variant_t l_vaIndex;+ V' b; J ~/ X# x: h; S6 J
l_vaIndex.vt = VT_I2;# }" ] N) J1 e* S
6 ? p2 K8 H- m6 _/ k
// 循环取得列的值
- E( v3 k% Y2 l& o9 y/ K9 g/ G for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )8 o' Z# ?! P p; ^
{
3 k+ f! p/ U( B l_vaIndex.iVal = lIndex;6 a$ Y4 D8 K$ h8 f( G
, V; M1 m: U! D
// 取得字段值
& `0 J' z/ @9 t' v- G/ g- Q varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;. k; o/ j% U3 a$ b- Z
}
7 t9 G3 [) \/ B/ v, U# ] return S_OK;
5 p; a, Q8 G7 X% n- Q }3 A8 O2 i1 N( f6 m: t/ D* i( u
catch( _com_error & a_pComError )- l# T3 x8 U$ J& \
{
) F" l3 N1 P/ S$ k …. // 错误处理
$ N% G7 F7 {, H7 T return E_UNEXPECTED;
/ s& L- g; x$ B6 A }
+ {4 |2 d% Z- w+ ?; R2 T7 I6 P4 D catch(...)" |* Y7 D5 H% x [: N/ b) L
{
$ P/ R# l, Y( I( z …. // 错误处理
% ^; d/ m3 t. Y- L& @* _ return E_UNEXPECTED;
' [3 b6 Q+ ?0 F) `1 j& n }
7 R* s0 b7 e Q}
$ y R, G3 {# O) J1 j# S/ |) A' f. ?3 \0 V
! U1 m0 {) V6 Q7 L& n8 ~ O
7.出错情况下错误信息的取得
T4 h# R3 o& Y; X6 ?
Q9 |, X8 _' B! u' ]$ {; k: Mvoid ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
8 S, A8 A+ Q' R2 V5 [# N{
) J5 ~, P1 P; h) Y- ^ // COM 错误取得
/ j: [. x. q. D: _ // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常+ A, D0 {2 `8 l6 o, \' m
char lpComErrorStr512];
2 M1 P2 ~; m+ }* ]/ k6 z% {# R+ |0 v) W8 \
sprintf( lpComErrorStr512," |: T( N w0 ^
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",% |( @- s- d. N* g0 j! i
pComError.Error(), // 错误编号
3 R7 M4 I8 c) }( v) P" E+ P pComError.ErrorMessage(), // 错误信息
; i( Y- f+ k# L! r; @, a (LPCSTR) pComError.Source(), // 错误源3 z, \+ p8 U2 h0 f: Z" c& O
(LPCSTR) pComError.Description() ); // 错误描述# n) {3 ^& u$ F& p* U
- B7 _7 M% h$ s ^3 m; P$ K/ k
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息4 O/ G+ M# q( }4 \1 Q5 p
// ADO错误取得
+ I2 J/ e& z! e+ g3 v6 `: V2 s$ E1 v
1 n4 c0 w- A" I$ P6 S ErrorPtr pErr = NULL;
/ u) ^% q) I! G. ~4 l4 `8 A) w if( (ptrConn ->Errors->Count) > 0)
0 T* H1 Z0 T9 U' w& W% p {5 L2 a: l F/ n
long nCount = ptrConn ->Errors->Count;2 n2 R9 C' n, f' W
for( long i = 0; i < nCount; i++ ) Z! k6 R! j$ z! ~, j
{
$ s X% ]8 v. D4 G) w pErr = a_pConnPtr->Errors->GetItem(i);& I) J* ~% i. }) k" }( L
$ B; F- _$ M! ?' V: t; n% r char l_pchErrorString[512];
- X, J/ H6 Y; k$ L1 F% A' F2 y) t sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
! \# ^+ c6 K( k pErr->Number, // 错误编号
3 m3 H) `# G$ M% O2 m' G9 I pErr->Description ); // 错误描述" y/ V( T2 B2 H0 F
}
, \" O) h) ?& S% O1 H! r+ \' t# q }0 `, s1 e! ?' i; T2 C
* O9 `0 s4 a+ b4 u* l' W
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问% M5 ~+ e- Z+ a3 N, Z5 J3 u8 H) @
// connection 对象取得错误编号和错误信息。 |
|