|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。( @& q# R7 R& l; g: u# Q
/ e+ t# g! D& X2 U1、 用import导入ADO 的 COM 文件msado15.dll
2 q7 x1 j# `, J2 ^1 q. @; }; F6 K6 G1 P6 ?, J
例如:) |* w: y! P. l. |
8 o' O( \- c; K: g
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
/ A$ x& C$ X) Y, y8 G9 T
% ^ P0 i# t$ I5 p no_namespace% \* e' c H6 _; a! j3 F7 x# S
; `1 e( U! P2 }
6 x* U5 e. }- ]* q, P( {& N2、COM 使用时初始化9 z+ Q8 K- A- O3 K& d
' x( V6 `, \' o' i$ PHRESULT ComInit()
$ u. e9 G6 I: J1 u- r1 x6 Z& g{ % D) Z' X) M7 R- E1 h/ H4 [8 H
HRESULT hr = S_OK; // 默认返回值# \' A/ D0 O8 M. O! R
if FAILED(CoInitialize(NULL)) // COM 初始化调用4 s/ B5 u9 O2 s3 q3 |
{8 b" L% [3 ?" O
CoUninitialize();
/ [. A, |1 B' P4 |0 Q& S q4 A" l hr = E_UNEXPECTED;0 K+ y. s/ P* K" A1 s9 I3 c" I
}
/ t3 }; }/ n7 Y' F return hr;
6 q0 ]- Q% \3 J& C' x8 T}( i" b0 M. n7 @9 ~/ G$ x5 c
6 J5 C1 B" w9 R" H# D
5 R8 j7 W3 q! q% z3、建立数据库连接
8 N3 J) a. x2 M2 J% Y: V) W1 ]7 t5 F s$ f3 f* |
HRESULT ConnectToDB( LPSTR pUserId , // 用户名) J p7 _4 s& A+ c8 M/ S6 _
LPSTR pConnString, // 连接字串 8 e) L6 v2 V% t5 o: @: w0 b' O/ V
LPSTR pUserPassword , // 用户密码
: ]' @3 I& i, M0 b ConnectOptionEnum ConnectOption ) // 连接参数) l0 Z E2 a6 O. _. f/ x
{
8 ]" Y$ I9 C' ~: ^' o3 m
3 U( I* D9 T. B$ D HRESULT hr = S_OK; // 默认返回值8 B" _# B. D3 _. N. n
_ConnectionPtr ptrConn; // 定义Connection对象% Q6 x9 m; g( f: B ]
: P' N, @! e- x" h( ` B7 a$ l! ]& ~
try
9 X: s3 N/ H2 Z {
' u* {9 T5 Y9 m // 创建一个连接实体; b4 u* Y8 e) x0 u! d7 Q' A
hr = ptrConn.CreateInstance( __uuidof(Connection) );
' ^9 Z* K+ e; z# [* u$ `6 i1 G" _" y# ^1 g: _+ Q
// 设定连接等待的最大秒数,默认是15秒
Z5 P, ^8 Y0 X( U ptrConn->ConnectionTimeout = 20. O/ |% ]- c s7 Q& p& m7 ]
9 j" n% h; F+ p/ b6 r4 O% s
// 打开连接* q- `9 {9 u) n J2 s3 D
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );5 z+ n+ x3 g V4 [
return hr;& Z3 E; l1 b: n3 {, q6 o8 k8 K7 E
}& g0 s& ^; _" j A3 [' f0 H4 r
catch( _com_error & pComError )5 L+ K, @8 G! P
{4 m# P* Y6 b2 `: B9 e8 I7 u; d
…… // 错误处理. v+ \) _4 z0 N0 l" i# V$ B
return E_UNEXPECTED;
V; r# V8 Y5 m }+ d: R3 w# m2 F, w+ |% i3 ^% U
}
; ]) @3 U% n+ I) g
# K, {' ]/ a3 m1 \2 p0 U
* I# _2 B' X8 d& ?9 L( ]4.执行一个SQL 查询,得到数据集(recordset)
" U) k6 H/ @3 {9 R/ R: k: w8 {' t8 \/ J
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )) y2 O) N/ \ a% b' a# Y
{' N7 _% v& \: c) i
try
# B+ N/ G4 ]" p. u {$ j' @/ u2 \' c
RecordsetPtr ptrRS; // recordset 对象
/ s5 \0 K7 O; `. ^) N ]6 }% q: T, [' Z# X" I( `
// 创建recordset 对象实体$ y3 s& Q' \, H! u; ^
ptrRS.CreateInstance( __uuidof(Recordset) );
% n. _/ R6 w' D! d# Z" K' w, T ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, ( P* `( V( X3 i' ?5 @: M
adLockUnspecified, adCmdText );8 k, T- j8 t8 J7 b7 M$ D. h
/ p) s4 `9 c8 p/ H2 e# t4 s 或者
g- E0 f3 z, h8 v ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );+ z" V0 L+ V* N& @& J
return ptrRS;
) H, Z# j9 ^4 i% y8 H7 B }
h1 p/ z# ?" {+ u% w catch( _com_error & a_pComError )+ R5 ]. t, ?- B# u c/ i8 m
{
* b- t' L1 q: b0 ?- T. M6 Z- I ….// 错误处理4 z' ^) N2 z( I3 R' t2 G& ]4 c" z6 r
return NULL;
1 i: y% q! C, ^( F1 g }
( K' u! j1 _2 b2 ]}
- q! b0 D( b, x2 r7 d
0 ?3 b5 H- U: Z# p# B1 e
, @( Q9 h& S) a2 ~5.通过数据集(recordset)得到列的名称/ _& e* y8 n! g
8 T, p3 i* b5 pHRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象$ l5 `5 x) ^3 Y8 l# W- ~" p, g
char strColNames[][255],1 M. _5 V4 B/ v- T- n( m
DataTypeEnum iColTypes[] )
* r. _$ D+ R8 q6 l- c( x{
! W" T% i# j, ]- t. v try
8 E4 G0 ?$ `5 O { // 参数变量
; T0 E( j. c4 y R1 P( l' Q _variant_t l_vaIndex;3 s6 u$ s- V' a2 \$ L0 P
' r8 @9 ^: T8 H5 i/ L/ U
l_vaIndex.vt = VT_I2;
' m) o$ q N2 B5 v* j; v! {- P0 ]2 g, P) ], H0 M/ U& s2 ^* P8 T
// COLUMNS总数
, A9 i% X* S! U- f0 G1 V" j4 H long lColCount;
/ B' b7 S* ]/ @( ?+ J) J" C1 ?0 r z
lColCount = ptrRs ->Fields->Count;
8 ?1 b. Q) B k7 k" n& M, u% J/ t# R7 R# R7 p5 i! y v
// 循环取得列的属性和名称
4 [5 _* R- m3 {' m for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
3 o; q, f. N9 n0 X: [( q/ ]3 P1 n {7 G: z% ]1 h" i& m
l_vaIndex.iVal = iIndex; // 设置循环索引
1 a! g q' C% [" z0 O0 W- _+ V! E
* i6 t7 }2 q8 U7 r // 取得字段名称
& G4 B1 Q* i( H" Z) @ sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
/ e' P5 m5 m& J) ^. n& t
) A1 Z/ Z) c- G! L // 取得字段属性2 X3 v, |5 q& w0 `4 H( z
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
2 h$ n# B# S; _: D }
o9 O5 C+ @* O. y- I( n( m return S_OK;; Z6 d0 w. [+ I3 m: w
}
$ \0 ]& v$ A9 j catch( _com_error & a_pComError )1 H* u& ^2 u4 k: W
{
5 |0 }- D2 c/ n0 p& f& n …. // 错误处理) r3 |% g* j7 b1 f7 \ V! p: G
return E_UNEXPECTED;$ w. b% U) v; x8 o) v; J) D1 ]
}6 ^# B( Y* x7 n- ~" s$ b# s( M
catch(...)& X$ z% k$ D5 l; k. [
{8 `: k$ }9 j& A# k! h9 V: G
…. // 错误处理
) T, R( X$ u: h1 L return E_UNEXPECTED;' }! \6 {4 G$ U% K( b) E) J
}
: P, Y$ i8 f+ z% }}6 Q7 Q: W. ~7 U+ X- m
4 T1 f( |: G+ q n
4 B3 J' f( G6 |6.通过数据集(recordset)得到当前行记录
' ?$ G7 @1 F3 e, l. B! t7 F+ P: Y1 @; p: W
HRESULT getOneRecord( _RecordsetPtr ptrRs,
1 J& [3 b( t+ T5 r! }) j const long lNoOfColumns,
) J8 B! V7 D9 l _variant_t varValue[] )" R7 D) Q. Z: [4 S" @2 e0 o
{: r* [+ y# W {8 o: c& A$ t
try- {2 |* o5 g5 P1 i0 ~: \ e
{
2 A6 F5 }( P: G // 参数变量
7 N7 `" F) h; j! u; S _variant_t l_vaIndex;
! p/ Z; b4 g0 v6 D l_vaIndex.vt = VT_I2;2 B' \6 P0 m. h- H$ m0 H
! e% \4 W# n2 ?0 M2 ^& d
// 循环取得列的值0 L/ F5 U [; C' d7 P! T
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )5 t8 a9 z; P8 o- H2 j$ S8 c
{
( H' f! o# j1 l/ c6 b* e2 O l_vaIndex.iVal = lIndex;! e' x; s2 k ^9 Q- D
5 `3 S# }; Y2 G. Q, R2 p
// 取得字段值6 M2 O+ ~$ Y! w
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
( b* Y N1 s/ D9 {. R0 I }
7 z+ z; |- p1 J return S_OK;1 j. r2 ~% J/ V' h; G
}
6 ?$ _5 A( a' k2 M4 Z catch( _com_error & a_pComError )# ^) w8 G; B, a3 F6 L% S, g- z. G
{
3 D/ q8 V1 G' e3 K9 } …. // 错误处理3 a! `8 U u% i; r& u5 ]. x
return E_UNEXPECTED;
( ]+ J( B2 P& f# a0 R" f j }* W( S5 G$ V. a3 I' m* p
catch(...)" J5 k3 t" P" e8 N7 P U
{
' m4 j. C1 ?1 k" K: t7 Y& i4 s E …. // 错误处理
! S, @9 }+ t5 B" v return E_UNEXPECTED;
% w/ A& e$ P) u2 Q) ^3 F }% Y4 [' A8 T4 U; B' w2 c1 U! v
}: a, y; c+ n8 n
, I. f- i# f% {2 O- b' m
! _9 Y8 F2 y5 o7.出错情况下错误信息的取得
7 j3 U& L( d" |+ R; _ q
( |# v3 n, I# `2 vvoid ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
. ~( Y5 z. C; {4 f5 W8 N{
4 Z$ l( B, C2 D& ]) W // COM 错误取得! k6 G1 o0 M+ w; _7 f8 Y% z
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常" F* i# w9 e; s
char lpComErrorStr512];8 v: q: e* a! f* A0 N% d j
; I; y6 ^) ]6 p3 Z, ] sprintf( lpComErrorStr512,. G3 m1 @6 @$ H* A' j) Z6 U
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",
! m/ i& E% }0 f' D, ^ pComError.Error(), // 错误编号
) ^6 _% x( X7 m3 { pComError.ErrorMessage(), // 错误信息
+ O7 K' x3 s# p: ?1 P2 U4 X (LPCSTR) pComError.Source(), // 错误源* r; |! d3 s2 V: W: c
(LPCSTR) pComError.Description() ); // 错误描述( e1 ]; P; \# ~' y2 l4 \- L
$ |; A! \8 \& N2 }6 x+ B6 P, F // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
( ]' [) e/ c* p R- j/ T. o // ADO错误取得- x" R7 d+ d+ X% A; F
7 R3 a: G0 l. [0 d- t! A, {, m ErrorPtr pErr = NULL;
. L9 G* x; A+ \* w5 `. P if( (ptrConn ->Errors->Count) > 0)
# Y4 a4 a% e7 M9 k {( J# X8 m+ r6 U- O; u% f
long nCount = ptrConn ->Errors->Count;$ k0 Y; y W; e/ e9 I
for( long i = 0; i < nCount; i++ )
/ k' }0 M& O0 [( E: U' ~ {* B" c, o5 g, I+ \
pErr = a_pConnPtr->Errors->GetItem(i);' \9 v9 A Y5 g! r3 L
# |/ r4 }8 q9 N' c char l_pchErrorString[512];
: U! R/ c( y2 s$ Q2 e9 @$ o sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
7 p ]- {) X0 I! K" ^! [ pErr->Number, // 错误编号7 S# b- g& S7 |7 c
pErr->Description ); // 错误描述
$ I. I, i3 V' e* \ }
# Z( h7 H6 N& |" C }& s5 i7 o$ T {$ d; K4 M9 Z
% V/ [/ L! J6 Z* B) x" r // ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
8 O( j5 m! y* ^3 ~ // connection 对象取得错误编号和错误信息。 |
|