|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。3 S0 ^6 a* j7 f+ `4 `5 V0 [5 O* ]5 ^
( R* h4 q6 z% @
1、 用import导入ADO 的 COM 文件msado15.dll5 M6 i, ~2 b5 H
# x) l" c) u% _( P例如:- R- q+ ~& y5 c P6 l# J# H. t$ w
$ c* R! T6 ^# ]7 M) ^
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
5 q0 b1 r( V7 N& T% ]; B
* Q8 B7 K2 H2 H' A+ _& s: m no_namespace
% f, Z* x" @" }) d# s# V* i- b+ _! Y" G f! \( P& N: d
: ~+ ?. q* m6 e2、COM 使用时初始化
" q) k( U* u9 e8 W6 g. N
+ r5 N7 a* k) }+ P. f! J0 w% T; jHRESULT ComInit()) x8 i+ J" q Q: r2 @- v
{ ; S/ k+ b k4 W- m* |
HRESULT hr = S_OK; // 默认返回值
: W+ {. Y v8 W, ^. ?4 `5 b7 p9 G if FAILED(CoInitialize(NULL)) // COM 初始化调用
* F6 ?" J8 q1 ~4 S5 ~% y9 Y {
3 ?6 U& K( M/ l N( F CoUninitialize();
" W @$ l2 M2 u+ D3 ^2 l0 l5 a hr = E_UNEXPECTED;
6 \4 |, W# I( ?4 E5 n }3 |+ ]! A6 A" _
return hr;4 d6 }/ Z% Q0 Z( ~5 j
}4 l; b+ Q7 @ n& t0 L) E- Z4 ?
! F+ P) P1 G2 W+ H" _
3 [) @& f1 s2 L& i) b8 P/ i3、建立数据库连接
, h8 \' Y' l% `: l7 g0 ]9 o! W3 S7 r* J6 I
HRESULT ConnectToDB( LPSTR pUserId , // 用户名
$ d T K) v1 |; l. X2 D( g% O7 v. s# z LPSTR pConnString, // 连接字串 : s% ^; n: t! [% ^5 X+ Y, H1 g
LPSTR pUserPassword , // 用户密码1 X G) r Z8 @
ConnectOptionEnum ConnectOption ) // 连接参数6 r. i3 M2 X/ j( R. l
{
W4 ]; u7 O9 u5 @' k; ^2 w: D* ]( r( A0 p9 { b2 x
HRESULT hr = S_OK; // 默认返回值
/ A7 V0 p! Z9 p7 H( j5 U2 ? _ConnectionPtr ptrConn; // 定义Connection对象
5 y) f7 T6 ?& R6 D( O4 ?* }# Y( P4 F5 j2 @
try7 |' Q% o9 h: B0 M
{
9 L2 m* B6 f* C- q3 v4 d* S // 创建一个连接实体
4 ], b5 [1 G S3 Z- c! N hr = ptrConn.CreateInstance( __uuidof(Connection) );, q* x( i& ^8 w: U8 \. Q
* S6 X' q: P# m9 ^2 _0 C
// 设定连接等待的最大秒数,默认是15秒
+ m$ o9 B! F- `1 i! k ptrConn->ConnectionTimeout = 20
$ w. i- W$ ]; H6 m0 I9 }- N+ u( Q% I. I( J, U* _& I$ Z
// 打开连接8 j! a4 N2 L4 `) W2 a- J3 y3 u+ q# @4 P
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
8 D( d, m3 ~6 D1 J2 h return hr;9 f8 F# r# i& n% o& q
}# B) }& }8 J9 g7 \- q3 [- F+ ]7 N
catch( _com_error & pComError )
+ {1 q7 m+ A# @! H {
k' M: \1 w" Z% Y: e …… // 错误处理
8 i O y6 R" O! a: f1 ^ Z7 m$ d1 @ return E_UNEXPECTED;
: {5 O, O1 O& F2 b }! w! S# i; N2 A
}
! I" w E2 s8 |1 O6 p7 b5 m( ?; A" q) e, ]
& y/ n! K( F5 r( J; H+ ?/ x4.执行一个SQL 查询,得到数据集(recordset) P' A# z& O! s8 j
: h$ X+ {! C% _
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )! J+ N* X% d2 N" b
{
; U9 v5 Q2 w; g( @$ A3 ]/ i try2 A, ?: A# a9 f" d$ M
{/ j0 Z# {- P4 G( B# F4 e
RecordsetPtr ptrRS; // recordset 对象
" m- c3 h: d8 P5 l
$ w; E" {( D" G0 m F% P8 m% i // 创建recordset 对象实体: `1 U' v" ^# Z7 F( A
ptrRS.CreateInstance( __uuidof(Recordset) );. v; q" f2 z5 w+ E0 y9 ~
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
8 o4 p6 m6 e0 x% ?7 badLockUnspecified, adCmdText );
. `6 u+ B( S, C3 f
3 [8 F: I4 E. z$ M$ t 或者) |( x i+ y! ~: A( j
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
6 ]$ F- i9 s9 M4 {# y return ptrRS;# O3 `8 I2 g& ] u1 W# I
}9 F1 K h/ C- Y4 y& c9 `1 l* u
catch( _com_error & a_pComError )
1 E: X E0 n8 U/ k {/ }; [9 e, i8 w2 W. |4 F+ X1 F
….// 错误处理7 T) l3 w& v( L- M! m) d/ W
return NULL;
P; q0 e$ I; |7 C. c9 g6 O, ?# e2 l }9 [5 o% B0 p2 M1 c4 |+ o/ ?
}
4 R* B! @: }. t2 b ~: L& b9 p& `
. l/ x# ~4 t1 [2 L# \
T% Z: h" S0 g3 P8 c+ t) I, w5.通过数据集(recordset)得到列的名称
* h* x. T; W* _+ L! M( k7 z+ b* M( r* k! G/ i3 p
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象" N6 T" T7 S m7 ^% H
char strColNames[][255],: p8 Q- v; @% X5 ^5 l
DataTypeEnum iColTypes[] ): V1 d( {- |0 i0 I6 X( L
{
4 B0 \- f8 m% m: ^& V3 C try
% m& [1 `: J( i { // 参数变量6 Y% }. x- ]5 O" N2 I$ N
_variant_t l_vaIndex;
; @+ x: k6 @$ _# }1 g7 X. @
2 E8 W# L6 {! N" G- j$ b: |7 u$ T l_vaIndex.vt = VT_I2;6 T- R! Y+ t" Y2 H9 X
* v5 L6 H7 E6 Q) k1 \7 o // COLUMNS总数
7 Q2 y- `3 I& H6 m& D% @+ d7 \# `, w long lColCount;
@* X& l$ H5 R1 D5 V$ f) g& ~" L8 F! ~& j: i5 \) B4 M
lColCount = ptrRs ->Fields->Count;# n$ u0 D4 ^# l! _4 W" }+ O% d* i3 Q3 N
# C# q1 x5 h$ [) ?9 _; } // 循环取得列的属性和名称
' G; o& \/ u; i/ P& ~- C for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )+ v* z0 Q" H* z+ m# P
{) s& M3 }( f6 C f
l_vaIndex.iVal = iIndex; // 设置循环索引: I* j+ q* r4 z' V A( i/ t2 \* N
$ B4 G# a1 t% |/ k& a a // 取得字段名称
5 O9 p6 t3 d0 z3 _ sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);/ ~& y7 v- {* y; o3 ?- |
( e" W$ _' m0 ]9 v3 H1 [ // 取得字段属性3 [% m. r ^ l9 C4 f
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
) H% e; {, J: f7 _# ]4 i W }; z, r) b4 v0 v
return S_OK;# Z1 U* F6 l; r
}& V6 q u& x- W) ], l2 L
catch( _com_error & a_pComError )
! t6 G) S' L5 r b- c" p {
" A" A8 F7 V0 W3 C1 N' K …. // 错误处理
& Q3 V) o' p7 t$ h( Y% w: M return E_UNEXPECTED;
/ P/ I# s H9 f% d }7 G( f) l: H# F% O
catch(...)
; `3 ^" o( ?5 T9 [4 U# ^3 n {
' N- Q$ I2 r& A* n; o! n …. // 错误处理4 }5 X9 U" t( V ^& Y" L
return E_UNEXPECTED;( T6 d5 k! F- s) Y; ^/ |. w
}" U; S$ X0 A6 E4 }6 q: x- j2 p
}
. b1 L9 S, T3 V7 t0 h+ I$ q
% f7 c9 {4 \" W! [& ^& V) q% G& E
. t5 }! C* v) N( a+ x, E* [6.通过数据集(recordset)得到当前行记录$ x5 ?' k9 c( i8 K) E) O
4 `& v. i1 w9 I- KHRESULT getOneRecord( _RecordsetPtr ptrRs,
* ?6 ?) _9 [" y. [3 Y7 o6 R2 ? const long lNoOfColumns,5 n6 E% d0 B' v) V+ K
_variant_t varValue[] )
) S$ E( k/ r! s: p{( J& U0 D V' ]( R2 z$ S2 P8 V& V
try
6 ]; H* ]2 W# p& z% B$ ? {
% b0 e6 y# c( b. E# P // 参数变量- D/ z @$ t: k; n4 Z
_variant_t l_vaIndex;
' r/ p. \) e% l* x8 p) Q4 p l_vaIndex.vt = VT_I2;
o3 ?$ j7 J, h1 N% |2 w4 f7 ]! R9 [7 \8 E, H: T
// 循环取得列的值5 V0 [# G% j: Q4 N% `
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
3 y1 G1 u' q0 O1 Z {
- j. f) F! I: }# y/ g/ i d l_vaIndex.iVal = lIndex;/ e& Q3 d8 W1 y7 y7 t5 |
/ ~8 P9 v! j: I5 r
// 取得字段值
# n4 K% u# o' [6 p, o9 m2 s varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;0 K+ q( C+ Z( P, k
}- p8 L8 Q) C1 K& z0 K7 H. C8 S
return S_OK;
# ^) h0 V( h' \ }) `* u( {) V" x' X9 r' I9 p2 C5 S
catch( _com_error & a_pComError )
5 B+ L5 C ^/ o" J5 J {
* [8 h1 T+ |) g) I …. // 错误处理3 x2 z& {" a' O
return E_UNEXPECTED;( D& s6 D4 X( c0 G8 S
}: p7 n9 C) x9 l" g1 q
catch(...)
' S8 A4 i2 f# N; T0 D/ U! I {
* v/ C* ^) ]% Y6 F" h) \5 T* O …. // 错误处理7 V M: Y* r2 i- M% M. q! t) q
return E_UNEXPECTED;: N( L) {0 c4 |5 ^% c/ V& b# s$ t
}
0 {* u, {8 D/ Y% |}
- U" @/ B/ t7 g ^. l/ b! A; N: H* K) Z# h! E0 n; G. a
2 [, {! V6 x" i7.出错情况下错误信息的取得
5 q7 K1 S0 R) @) G& ^4 T x# l/ c& n: h! U5 c/ O9 P9 A
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );- p, Z3 Y1 ^$ f( Q) Z' f1 T" }
{
, b$ l, L: c0 y8 R/ u // COM 错误取得: v: B- K9 p, Z" @7 d5 Y& z
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常$ @/ V* G+ [7 w! D* t! w* c
char lpComErrorStr512];
5 Y( h1 r! V$ P+ f9 v% [- E+ g7 E2 _
sprintf( lpComErrorStr512,
4 z" G. ~1 ~# C# U "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",
! \9 L1 X: M3 C$ F" T% x' L9 F) b pComError.Error(), // 错误编号
/ a9 _& o* p+ j3 u+ q- \* p pComError.ErrorMessage(), // 错误信息
) F3 y7 `" ^, u9 ^0 I# b (LPCSTR) pComError.Source(), // 错误源
& Q9 B4 i$ _, ]/ q/ w (LPCSTR) pComError.Description() ); // 错误描述- @9 ]& Q$ H% T% O9 i: M
0 U" a) ?$ F6 q+ `5 a% Y3 Y // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
( B/ o. j. x1 [$ E0 z) w8 W+ {* S* {1 J+ j; U // ADO错误取得& f0 u. |0 B' O: I
e. r% H, D& C! T/ J' I; W8 ~. o: s
ErrorPtr pErr = NULL;
" g. \9 i. Z f3 e if( (ptrConn ->Errors->Count) > 0)0 ~. E* S& i$ \+ q2 n
{
5 n9 ^5 K* I) t% f, b; A/ c$ Y* t4 A long nCount = ptrConn ->Errors->Count;
" s# [* g/ H5 p3 G for( long i = 0; i < nCount; i++ ), G% O% ^, x& Z, a* C
{$ R9 I6 _. P: E' N& z6 D' F5 N
pErr = a_pConnPtr->Errors->GetItem(i);
2 l/ V @# O6 e7 e ^* p; |) z0 o- |; D0 p
char l_pchErrorString[512];
" m' V6 y# n- d6 L/ w$ L sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",5 Z3 U T$ V& Z: E. a: F
pErr->Number, // 错误编号
6 S$ M' m9 p. Q3 [ pErr->Description ); // 错误描述
1 Y! w: |# g9 r% R! S } ]- m, v( _8 H4 d
}: i) y7 G4 S* K) [/ t
8 g" P& H% a0 `9 k; N/ w
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
$ Q. ~8 i. ^. M) E5 w3 M // connection 对象取得错误编号和错误信息。 |
|