|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
k- ?4 \1 m. o# c+ k, w/ W2 F( y* }/ h: G( V. d$ e+ ~1 q' s
1、 用import导入ADO 的 COM 文件msado15.dll _' V4 ?3 x: x {
( H& O& z% [$ X
例如:/ y6 W0 T6 w5 l$ E2 B( w
+ u7 t. t2 {4 h7 J% B #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
! f+ r! t# Y B' I: |3 z7 K0 Q9 A- L" f# ]: h7 v3 g/ b
no_namespace2 M% ^+ ?, C# V( b1 t8 F6 F& S7 n- H
, J' V C" l! s T* v( a; {. A' z# R
% n) k, {( T& u/ I& G2、COM 使用时初始化
. a( W8 W3 q: @2 @7 x! U
$ Q9 n+ k( l& |& x" gHRESULT ComInit()
" g. {& |+ B! U" k{
9 i/ o8 \; L% ?0 a7 V8 K, x HRESULT hr = S_OK; // 默认返回值
5 u; z7 t' n$ k, U5 [ if FAILED(CoInitialize(NULL)) // COM 初始化调用- J" O5 a# Y/ k$ f# Z
{( `6 k" Q% ~" r. ?9 |2 k/ _
CoUninitialize();
: l2 T! i3 N G+ `, ^ hr = E_UNEXPECTED;
1 X k6 H2 F" I8 `/ X }9 Q q. Z- B3 k p) g% q
return hr;
/ t6 g: M# G; |}$ [- K2 A7 B& m2 X2 | ~; w3 u
/ Q) }* N5 w/ l U
0 M: C' F- [( Z3 I5 \' e% ?3、建立数据库连接4 Z: M1 L9 l/ o
8 E* b8 }- z; s( UHRESULT ConnectToDB( LPSTR pUserId , // 用户名9 n0 ?( C D$ f- H! \& S
LPSTR pConnString, // 连接字串
0 D: y5 Z R. u$ {6 c) D8 F' P4 U LPSTR pUserPassword , // 用户密码
. D) h3 B, b/ d5 d/ { ConnectOptionEnum ConnectOption ) // 连接参数1 X/ Y1 S3 o) _9 E4 T
{7 @1 P- b! E* U
; e/ L+ Y, i% P: m4 V HRESULT hr = S_OK; // 默认返回值# [1 {' \$ o' U1 D4 B: H
_ConnectionPtr ptrConn; // 定义Connection对象
" y- ^" T8 Z1 D( ?$ N9 B7 i
7 o+ j( l# o6 b; n7 w0 A try
/ `6 j7 ~ ?# c$ S: D' y4 X x {1 k$ |3 f% j; i8 u. l' O
// 创建一个连接实体2 C9 l$ L: y- @7 I( N2 e
hr = ptrConn.CreateInstance( __uuidof(Connection) );
$ o0 L# ^, k6 R+ T+ J3 v4 c
3 f0 Z: R; u& z4 k" T // 设定连接等待的最大秒数,默认是15秒" A* W$ n% B* S' ^/ [& K" m: I: ^
ptrConn->ConnectionTimeout = 207 n9 C% m4 I/ E+ E( {2 L
5 o7 _ i0 Z( a) S) @9 Z
// 打开连接
) h3 _* s0 F8 I) b( V: y hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );7 M1 K) ?( n' E( B
return hr;( k4 x& u8 ?$ n% T2 }
}
& L) w8 P% R" K* n catch( _com_error & pComError ). t. C6 O5 x( X9 x0 X. D7 a/ S# H0 O
{+ A5 ^: r4 S- M2 p
…… // 错误处理
- E3 k0 x7 G: z# X+ a return E_UNEXPECTED;
; F8 i& F9 L% W; A. C }9 M; s) C: Q$ _4 ?
}
, a; v3 y0 e9 z5 N+ D% D3 V
+ \# u" ? S7 ]- C
$ b* ^8 o# Z6 I' ~% u. O1 {* i4.执行一个SQL 查询,得到数据集(recordset)9 Y' m0 ?& a/ x5 p' _
& F; s n5 G" P8 K8 }_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
}$ `- }& {# Y: o+ Q{
9 G, H$ W& g0 |7 U+ O try8 p. g8 i5 [+ {3 z
{
+ s0 x1 Y; D {4 k T2 s RecordsetPtr ptrRS; // recordset 对象
7 T& X- a! T8 m2 y! |) ?4 H* b
0 V+ r) k% e) D1 \. V // 创建recordset 对象实体
1 [7 u2 i' ]/ S2 N" H8 F, e' R ptrRS.CreateInstance( __uuidof(Recordset) );
, f& }1 W3 s5 t: x) f3 @ ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
7 L% C( N- X5 V& B, |( iadLockUnspecified, adCmdText );( ^+ Q3 Y t8 i; Q% H
; Q8 {% a6 y- k, x: V
或者1 t# C! i$ F& X1 V0 ], b# @+ b I
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
: w% @) @7 V8 ^) b8 T, a1 P return ptrRS;' Z# s4 a6 Z! n0 U3 I# |7 u# R
}
! u+ P. Q( g, X( l, | catch( _com_error & a_pComError )
4 j4 F$ f, `* m6 E' @( r {2 E6 A5 i+ Q5 [' c( ?# w" t1 o
….// 错误处理, b2 b/ |6 I( Z1 D7 _
return NULL;
1 A$ [* q1 c8 l) m3 X } ?% t9 Z- R$ e) i' a, ~
}
: {! k7 k& R0 X! `+ A4 N
2 Q, X [6 D4 C: G9 C+ v3 E9 ~; i0 ~* Y# F$ \. Q0 \% [5 j. Y
5.通过数据集(recordset)得到列的名称1 r; Q! _+ T* G" [
, Q/ L- {, Q' NHRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象( _5 M: Q( C+ v0 S. V
char strColNames[][255],
$ }1 y; N9 ?" X h DataTypeEnum iColTypes[] )
& W% ]( @4 [* r6 j" R{
- V# l! H0 o2 H. F/ F try
# |4 Y) o8 m6 q$ K { // 参数变量$ ]) }- Y* J. S3 D/ ?" G
_variant_t l_vaIndex;/ Z2 _7 p; [" s' ~+ m
$ F) ~$ |2 C- F8 T# x+ i
l_vaIndex.vt = VT_I2;
5 d/ p" V: z2 h8 U6 U: a
: t' t) _9 p. k1 ? // COLUMNS总数
5 {, K( s4 O/ @6 T- i1 Z3 P* E* } long lColCount;, V( V2 ?( |& t+ ?! _
& F4 h7 {/ q7 O" @ Z lColCount = ptrRs ->Fields->Count;
, {; t. s( r! b) P0 f1 d
( E# Q4 w+ l2 N // 循环取得列的属性和名称6 Y. k9 g# |& L |0 Q- K [
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )3 i* U4 q* P, d& W* ^1 x) l+ t1 A; G
{. Y4 }" g4 E- {# f+ U, L/ B
l_vaIndex.iVal = iIndex; // 设置循环索引
$ J `9 _1 v J9 ]* z" [0 x- A. r4 i! G0 {5 |
// 取得字段名称 O- M' S& S3 q* [; a
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);! c" D3 O! }+ _3 E& n9 t; |* R- A
+ ]/ o: l% [# y( ^- U! X* z
// 取得字段属性8 v3 U! q. f& L I7 b0 W8 g+ d* W
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
- U+ A; Z8 `8 y* L2 B5 y }* }1 c' L6 l* P6 L9 F
return S_OK;
: @+ p7 |2 E8 R3 N& r$ h; ~ }, C5 {6 Q, c7 s
catch( _com_error & a_pComError )& T: ?; Z" \; T% j4 x$ w7 a6 H! k* M
{4 y% o9 q: A# z( B; y' e
…. // 错误处理
9 P' {5 G* O Y8 W. @7 c( l return E_UNEXPECTED;6 i1 H. V9 ~" l/ \$ f
}
: ]! I/ S9 ? R% Q, e$ [& W, }( ? _ catch(...)
! k& g6 }7 d G( u4 y, ?: G {: u2 c. Z/ W3 T8 a7 S* |3 i7 D
…. // 错误处理
; T; x/ M& n% V* @4 m+ ^ return E_UNEXPECTED;$ |) w5 h5 B& I$ V
}
& l* \5 r/ j1 P# X. i}+ i7 M! F- a% T
6 R, f" h# b; I3 l l$ X% {3 f( U9 W+ j2 ]
6.通过数据集(recordset)得到当前行记录
+ H9 s! ]4 E" G3 \( I0 s
3 w) a I# Z0 ~( z5 W9 x' K4 JHRESULT getOneRecord( _RecordsetPtr ptrRs,
$ f. M" l6 n# I. M7 e; I const long lNoOfColumns,5 ?) G9 n; b3 C
_variant_t varValue[] )' e9 t! f7 ?: O
{ H/ i3 H) i6 d3 F
try9 T1 R# I: o1 \) k
{
/ r/ `& C4 E! \7 V9 _ // 参数变量- M0 f' C) E# f
_variant_t l_vaIndex;7 B( ?! p g: [) T3 k0 d/ k' D
l_vaIndex.vt = VT_I2;
! V* `+ U7 }) \8 ], g3 n0 _/ y9 R9 `& ^% A4 c7 V3 F
// 循环取得列的值; g6 \0 G7 A7 `1 ]
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
! ^3 t9 \3 b) c" ^5 P5 `# ]9 ?1 J { " ^" U$ T4 B3 u0 ]0 f. e8 P5 q/ A
l_vaIndex.iVal = lIndex;
; L X$ f/ p4 o* W) u/ b ?3 ^- z2 w4 R% P
// 取得字段值' x; U4 ^% [! H! X( v8 L
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
m( ~& I. s5 B9 o) z4 S: t- } }
" F$ b @. c7 e. z$ s1 g+ d return S_OK;: J, W. a4 O/ V$ ~
}* y4 P+ X2 C* e% d7 |7 y
catch( _com_error & a_pComError )
& |& o5 I! O; q* C8 ?* K' g4 o% M4 O {& n; _1 R; a8 R1 \2 m( H6 `
…. // 错误处理
3 ?, m0 | c$ s1 w5 J. z return E_UNEXPECTED;' ~! W, w9 o( b7 C
}
' q2 @4 b! B2 @3 U catch(...)
! z+ a5 E3 G% n% u6 ~( |* n {
# c2 C9 i% E* a5 r- ] …. // 错误处理1 \. E( c) Q5 v
return E_UNEXPECTED;
4 B, Y3 n P5 { L+ a3 Q }
3 n- S) A$ D; b}8 ^1 ^3 z# x( P2 K G7 Q
( Q# l' q0 y+ S5 ~: o) U) Y1 V2 ?
7.出错情况下错误信息的取得! _ o4 P6 m% T e- c
. ~1 `" A3 A4 n! R" w, ?void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
) V, C7 y; \8 J- I" e{$ {8 o5 }+ U+ A+ n/ M
// COM 错误取得
; I) v' F+ T( ^/ x // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常4 T! k$ d/ Q( N* N- ]' y
char lpComErrorStr512];$ q9 |7 l& M* \0 I# ^
: O( }& N) B% p( k sprintf( lpComErrorStr512,# d; j( y3 f# @
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",1 T3 [0 s! {3 E/ \$ h2 i! r) _
pComError.Error(), // 错误编号 F6 e+ ?4 Q. q) R6 y) g" Q
pComError.ErrorMessage(), // 错误信息
. w# N; E4 `* o3 i (LPCSTR) pComError.Source(), // 错误源
0 X. J/ l8 e8 k+ C (LPCSTR) pComError.Description() ); // 错误描述/ u, l! T. I- z. [+ H4 S2 o: y
: Z4 R0 A( K0 m3 ^
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
" G. M+ t' r$ v- |, A. E4 E // ADO错误取得& X; Z" B' V6 C% h# M9 U
9 y$ w' e9 ?) h5 l4 B ErrorPtr pErr = NULL;
7 S9 }; m: z: K4 f0 t8 N* r. P$ c if( (ptrConn ->Errors->Count) > 0)7 L5 H6 D( [2 j8 z+ B5 \
{
1 _# T0 D5 S) H long nCount = ptrConn ->Errors->Count;
; h. z- P8 z j x$ d: c1 ^! r; @ for( long i = 0; i < nCount; i++ ): O/ O8 {1 h7 ]
{
* R! f: x) |! k7 ` s$ u! @2 `) p$ `5 r pErr = a_pConnPtr->Errors->GetItem(i);
7 `1 i ?4 z2 w8 e3 `# s+ N! _ P+ `% V/ {# j# k& A
char l_pchErrorString[512];' D- I" S, Q8 [
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",0 @# g- j( ^. p# P
pErr->Number, // 错误编号; [4 | N, K% q+ D2 X
pErr->Description ); // 错误描述
, P; P) U8 J2 S X; u }
. q! S H Q$ n }
3 a) U4 g, p! e7 v# F
7 K- P! k. Q, q) O! r // ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问4 {( M* ?2 t6 |5 v; e
// connection 对象取得错误编号和错误信息。 |
|