|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。* t' n7 n/ x/ E
4 J, K3 G Q: Z1 n0 h( m9 K1、 用import导入ADO 的 COM 文件msado15.dll
1 T' \) k6 s/ Q" I3 D9 l$ ^/ m. a
3 S$ ], M3 x0 C1 S, g; J: V例如:6 Y; [, n; H. m# W1 r" y0 O2 F
$ o- l. z- ^# `- o5 G
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
3 j6 p6 A% t1 f- w* Q5 |$ S, ?/ ?1 f u; X2 X
no_namespace
t& I# M! R6 Q& G R( A
9 h1 Y" ]. ]9 p. i; O0 [) x
) ~( I; {9 Z* P* B X$ m+ G! I9 Z2、COM 使用时初始化- o9 O+ @3 Z8 y/ Z O8 C/ m3 s9 R
+ P- }4 W6 k U: n+ m* nHRESULT ComInit()
& o) i) ?/ G& n u& O% g{
6 D+ \6 J) t* U- q7 a5 ~/ x HRESULT hr = S_OK; // 默认返回值
, {) h; e7 c# v0 N* Z if FAILED(CoInitialize(NULL)) // COM 初始化调用
+ y3 x: f8 `( t7 S4 ^ W* R) d {
$ L: @# }7 b. j- r& { CoUninitialize();( t: j& L9 `. ]. a6 {
hr = E_UNEXPECTED;
1 k* h4 W- A/ E }
" h* ?0 D B/ R+ s3 `6 g; Z5 P return hr;" E* G, }+ H8 B
}; ^8 B8 k! u: D) p: Y2 f1 `
3 S9 f0 X0 t& \7 f0 }& v7 g$ p
% o4 k' h8 `+ q8 E0 U) }$ y3、建立数据库连接
; i' \" P7 o% `0 n0 V u' H0 D( p2 E
5 V/ k$ i' G$ k" ]/ A) h0 ZHRESULT ConnectToDB( LPSTR pUserId , // 用户名! b0 s' Z- H' _+ w4 P9 g4 N$ L
LPSTR pConnString, // 连接字串
# D! {9 R% s! v3 ] LPSTR pUserPassword , // 用户密码( t: ^3 D# \' Y) y2 `
ConnectOptionEnum ConnectOption ) // 连接参数
. F# h5 ~6 H% X$ Y5 x0 b3 l' n s. y{
% ^# O) `" x/ u# S5 U# x% j2 d* I; H1 k- s; I0 U. Y( `/ B
HRESULT hr = S_OK; // 默认返回值
7 \& |9 t' j. X _ConnectionPtr ptrConn; // 定义Connection对象8 a4 m6 ^8 `& Q9 {2 X! K; h8 v
$ ~( d/ \5 k# y' i2 X& { try J5 n% H, B" `8 Z2 R, Q2 p, \
{$ I. Q6 m6 E) b4 }
// 创建一个连接实体0 |: F3 I" H. w& u2 f. G
hr = ptrConn.CreateInstance( __uuidof(Connection) );
7 S, r; d9 `7 B4 U4 h" f$ A
! V! |5 g. x. G ?/ s // 设定连接等待的最大秒数,默认是15秒
5 B! `" ?# L) Y ptrConn->ConnectionTimeout = 20! T- O' N* w; v' }" N
9 }( c$ Z- Q' N2 y
// 打开连接* a3 @+ _) P, O6 C- ]" \8 J5 D1 y
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );, A' `" C: m; y) N1 R( Q
return hr;
4 f* R' O N. e3 x* L }$ ^ {( d n. R! L
catch( _com_error & pComError )
+ @4 d, D7 w& B" j7 r& |9 ] {
" n! ~3 Y( \+ L) B( r7 m5 U …… // 错误处理5 J, i8 z+ _+ e/ Y8 @$ e
return E_UNEXPECTED;% i& X8 n3 [7 }2 E4 K1 x* A
}
6 R! y( c% S% B1 T}
! }% O: g2 p: c* t% C
. s4 q0 k7 W3 {! @/ K2 c6 i4 x% a. G$ z. q
4.执行一个SQL 查询,得到数据集(recordset)% [# p) ]7 v# ~ d9 L8 `! w
I. m" | [+ g$ d6 A' N% O* q
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
$ M) h7 S0 d; M5 D$ T{/ A; \5 K0 H* T6 [- V% j
try1 h& G: e0 `, x, ~0 ]5 x
{ ~2 f& h1 F, B+ _2 L
RecordsetPtr ptrRS; // recordset 对象- N- X5 i/ Y& u; T6 W
4 i! s; ~1 i" y Y' u7 k // 创建recordset 对象实体
0 |+ c% E4 L* N! {$ P+ x ptrRS.CreateInstance( __uuidof(Recordset) );& x7 z+ g) k6 i7 B% m
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, " c# L ^' }4 `4 w# j' b; W
adLockUnspecified, adCmdText );
# w* `/ j1 F/ l3 U( f7 X8 g- S: p K9 k! C5 I* g, U$ E
或者
2 U3 p$ Q3 ^. W5 L& I9 H ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
; @0 r: m8 j( N8 Q, } return ptrRS;
' I# L4 p( _* B4 | }5 y- q" k0 i5 N$ B2 z4 r6 V
catch( _com_error & a_pComError )) u, \0 ~6 X% u8 C7 Q$ m. L
{3 w' ]0 T- o- l2 O6 o( o
….// 错误处理
0 x! \) f7 `* k/ v return NULL;
# o3 X7 M. S9 c+ D! d9 ~% L }
3 Y% q, o3 @2 K3 g. N}
0 y# @! B2 \* Z( F3 n
0 z- t7 }* n$ G7 H$ u3 o3 W- n
9 M* t/ U. j) y" T1 Q5.通过数据集(recordset)得到列的名称
. ` |8 ]+ t( j( c+ V3 D; t% l
! b Y7 f. W% p3 d3 W6 gHRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象2 M, @" j4 o7 e: K. \& P k% H
char strColNames[][255],
7 d8 @3 X, k9 |/ U DataTypeEnum iColTypes[] )
* T0 E: q3 }' b8 n" n& t8 n+ ^/ P{
' |# j9 W$ d% Y4 }9 q+ m; J try, s) b4 b0 G- ? S1 m
{ // 参数变量
( C4 W! y- Z3 k7 o4 G3 f6 f9 \ _variant_t l_vaIndex;/ l2 ^( L; h% @6 @) P( Q6 O
6 Z2 q: G3 T! s' F# u l_vaIndex.vt = VT_I2;
, p! U* o, q, e5 ]/ P& W3 o9 i4 P# w* R w; v* h
// COLUMNS总数
; W/ w. C+ m' S7 p; u long lColCount;+ C- w) e8 Z. O: ~
$ A; G2 j' Q" d5 c* `4 Z lColCount = ptrRs ->Fields->Count;
8 G! ^3 \* d- ?4 Z- A: Q/ F& ~9 s& [+ s' E
// 循环取得列的属性和名称
# k: A3 [( \! Q# O" L" b for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
- {+ r# f e1 S' a) q0 y: u& O) | {
' @* D+ J0 r1 F) T& K. Q2 v- p. @ l_vaIndex.iVal = iIndex; // 设置循环索引
0 r: K' p3 l: A5 j) |7 ^
# C: Z8 i k' O+ @ // 取得字段名称
1 R k% l* y$ u J# O% _( L) R! X sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);& s) |5 ]6 W, _+ G
8 ?# o' h; t5 r // 取得字段属性
. I2 w" a: d% p. P iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
2 l% V( A7 {0 g( Z: t. A3 u. e! v }& p% ^7 I6 c# b% ^ O0 v
return S_OK;
8 I$ N+ D( ]; b9 ? }
. d5 o C% M. A7 g/ [( z# Q% E catch( _com_error & a_pComError )
% c5 J) A" K7 K3 T" t {
5 y( E( X8 Z- Y# G$ n/ \0 m( M …. // 错误处理! N- e3 @ d3 W" j2 B
return E_UNEXPECTED; p; n/ j; w, o, H
}8 r1 u5 K: H# f5 ^) k, t6 H
catch(...)0 n+ D1 ?( x% K9 [1 d" y" w
{
5 N/ A' z! R- ]1 A3 X% w …. // 错误处理
* f" t1 M. `5 g0 j$ e, ^1 C, e return E_UNEXPECTED;% E$ P5 ]: [' W/ _# X# ^- y
}
" g2 U3 S6 O3 w3 K G}/ }" G5 N. J1 Y4 {$ e
) s4 k1 X( Y! O
8 Z* n' ^0 E+ P9 H& W5 c3 u6.通过数据集(recordset)得到当前行记录
: o; h- J) N2 P4 o1 B/ _( @' S9 o0 d) z- H% g* r& R' } c
HRESULT getOneRecord( _RecordsetPtr ptrRs,2 D) n" c# q5 C( \7 U- e$ E, q6 r7 K
const long lNoOfColumns,
. W$ t6 D. O' K" `, w. H" n _variant_t varValue[] )0 t# Y9 j, S# X" l* [
{
; G9 M" }! X) b! X7 |' D try# u( ~- i* U% e: s
{* x, `; v V i3 u
// 参数变量
# Q t, @5 H9 z m( a' } _variant_t l_vaIndex;% l/ m9 o0 l; `
l_vaIndex.vt = VT_I2;
7 W7 R" q9 y4 }, j* u0 V7 \" I" g+ z9 V- T* c; u
// 循环取得列的值. w* `& x6 [* W
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )$ X2 }) f& p4 o6 f
{
1 {4 b' C2 S% s3 Z j. E# _ l_vaIndex.iVal = lIndex;
' c9 Q% q. \8 A% B% ~5 h' ~4 q% @" L. G& h
// 取得字段值/ ?1 _6 \1 p6 M% J3 z
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;- n1 q* h( Y* |
}
: ~' ]% O# h1 a" j# i return S_OK;5 p" o- E# z( J
}4 i( P- k, h3 r9 [: x$ E0 k5 e
catch( _com_error & a_pComError )0 D& M: Q& A# |/ m5 B
{+ |2 m \- b" C( U
…. // 错误处理
6 W. L9 N! t9 j: s1 Q return E_UNEXPECTED;
$ X! {: N, T4 [4 Y" U( W3 n) A }
. z+ W% F$ U$ p% j( Z catch(...)
0 d, A3 y7 a& Z4 T, F- s8 u' U3 b1 H {' b2 S/ k8 a. _
…. // 错误处理 U6 e* u# e4 y' { L
return E_UNEXPECTED;9 L1 c5 k9 H% v& x9 `
}
) D, d d. T8 r% I}
8 {% o8 S+ L& D; X7 @% P5 K& j( p, j2 R; |2 o+ d/ A
9 ]+ w6 Y g5 N9 ?& b0 u) w5 p
7.出错情况下错误信息的取得- k+ ?" M {5 E5 T
, ^1 r( X5 w3 n) Y* E2 K: H8 R, Q
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
9 ^ o' ^+ _' [: |{
! v3 _& m/ T3 {* ~! L6 ~% B0 L // COM 错误取得
: H- t- m8 B8 [1 H // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常7 x1 t* U5 S f8 l
char lpComErrorStr512];
" N5 M4 y! x b
1 d' j6 I7 a3 N* ~, x/ l sprintf( lpComErrorStr512,8 O0 E8 u3 Q& N3 R
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s "," h5 r1 g H2 B' ]
pComError.Error(), // 错误编号" n" e0 G& p& t3 w6 ?8 }
pComError.ErrorMessage(), // 错误信息( r& X, t. t" |7 f o$ y5 y
(LPCSTR) pComError.Source(), // 错误源' o. f: p( o# k2 I' Z- D
(LPCSTR) pComError.Description() ); // 错误描述
! B2 K# e2 g; G
( I- i" t( N ?! o8 M6 N* T // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
) L N, i8 Y4 j/ M q // ADO错误取得! u ?: b3 G5 `. U$ n/ U
$ y0 g$ K4 ]" W \
ErrorPtr pErr = NULL;
6 d7 c+ K$ m) A/ D if( (ptrConn ->Errors->Count) > 0)$ z6 V/ W2 x7 e( C
{
1 z% I- L8 \9 f long nCount = ptrConn ->Errors->Count;
' c) Z+ m7 F$ u, H& ] for( long i = 0; i < nCount; i++ )
5 U* I! @* X/ S u: o0 p {& {( G6 [% g. [: ?& u
pErr = a_pConnPtr->Errors->GetItem(i);
5 G9 Z; @/ F' r
& t+ Y R* z! ] char l_pchErrorString[512];/ a3 H6 G' e0 Z1 ? [$ Z; R
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",3 |4 _8 J; _" ` L. s
pErr->Number, // 错误编号9 {& g! v7 J% A/ d
pErr->Description ); // 错误描述
7 c$ @4 {% c& [$ v6 ~" @3 d! Q }4 @/ r' d8 P9 J" {3 f% I0 M* K" t
}
) y6 P7 ^2 @9 a. b( E
$ ]/ a% T( C* f F' o/ Q# S" z, ] // ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
- B2 I" F$ \2 d U* h& D // connection 对象取得错误编号和错误信息。 |
|