|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
! ^4 i5 r ~2 L& m9 Y o$ I/ | d% X/ F$ ]; b* Z9 Z
1、 用import导入ADO 的 COM 文件msado15.dll( X* x" M2 Q; C
a' p V: e* {) `例如:( q' R' T9 A5 y
# M6 n1 D: T! O' l. _6 q( K #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
: }; S. O, h+ J7 h; L4 o' ] p1 O T- C3 O' X; @' o
no_namespace! c& U, S7 _$ v
8 o3 E1 D [1 F$ G% m; D
4 X, ]! M* |% W) S% C
2、COM 使用时初始化
& f- u. Y. v! @1 I K. K4 m3 Z9 i) f+ y# J4 o0 I- e% B' [+ R* B# W( j
HRESULT ComInit()
# ?# l5 f( ]4 q1 K$ k) E{
) a: o" N8 p1 Z! o* M0 x, F HRESULT hr = S_OK; // 默认返回值
0 C* E! E: z. P' ^! y8 k if FAILED(CoInitialize(NULL)) // COM 初始化调用, y1 v! v& [: x/ `# K
{7 x4 G) `2 R; R/ \7 t. J
CoUninitialize();
. [, \- j$ F s5 g7 P/ K' n hr = E_UNEXPECTED;! k: f( R6 q' B* H' A/ ^
}
7 q. ~4 B" S7 R: l x return hr;
{0 i9 e' E7 }5 e- v+ m% f}2 ]9 o: D- F5 ], j# _
+ k/ B& z7 k3 B& S# Y! K' p" ?- E' Z; u' n$ U
3、建立数据库连接
0 r6 l+ l$ L3 X8 n: Q6 G# R
/ j1 s- K* |+ v& S2 e+ e/ LHRESULT ConnectToDB( LPSTR pUserId , // 用户名
9 T" `9 n& z0 x LPSTR pConnString, // 连接字串 G4 K9 J9 |7 O# W" t
LPSTR pUserPassword , // 用户密码- G& [" v9 r+ U
ConnectOptionEnum ConnectOption ) // 连接参数
% J2 I# G0 n# y' w2 [. i. k( b{/ H% G; V! `/ Q* F, x P8 v7 E( v
3 ~0 ?, E' `) V2 f
HRESULT hr = S_OK; // 默认返回值4 u( U; \) [7 \" e* S3 _3 C
_ConnectionPtr ptrConn; // 定义Connection对象
; Q7 Z' D& J% \ G P& u# M- s! i9 c. R
try
- g% H2 f5 T t {! _/ H% Z6 J$ L9 e. v+ z
// 创建一个连接实体
+ X5 M& Z5 H$ |7 X/ ]8 l+ ? hr = ptrConn.CreateInstance( __uuidof(Connection) );, @3 z: i/ E* ]) O+ Z
! B, `. `3 c3 ?$ r5 E, W: c
// 设定连接等待的最大秒数,默认是15秒% X6 ~1 U9 j: e
ptrConn->ConnectionTimeout = 20
. s# q4 t/ Z( O
' f/ Y0 s( c( X) x" ] // 打开连接
5 I+ G( b, e6 y hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption ); X& S* H9 c% U$ [, K
return hr;9 }( h/ E$ P }4 j1 m& I3 }
}
8 x: N4 E3 C- ] G0 ~! z catch( _com_error & pComError )
: H1 U$ q/ D; z! G% l {9 b5 A) |6 Y) C
…… // 错误处理
2 P/ {/ `# d4 E" Y6 d return E_UNEXPECTED;
: L; H ]& U5 u; Y& C) x0 m }, y, y' ~- A% i: x2 U4 [" F9 k
}7 \# P b4 v, j: B
0 x _& [7 y/ S- ~; W2 @+ e% O! `+ i; v! A* B8 a/ ?5 e3 I
4.执行一个SQL 查询,得到数据集(recordset)% Z. Y0 N9 E& S" h& i5 r8 b4 H
; _% \5 I, _% e/ __RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
/ g9 D/ |2 G+ s' ]$ N{
& F9 R( F9 E5 O% i' m try z7 }" A; _/ l: p3 L9 L+ x
{
& v0 j% a: x. B S& h RecordsetPtr ptrRS; // recordset 对象
: U& \& c& j' ]+ _3 W
5 l; ?9 V+ r0 o% s3 |$ ~6 o# x! R // 创建recordset 对象实体
& ^4 Q% |. a2 ?$ Q5 l3 \, } ptrRS.CreateInstance( __uuidof(Recordset) );, g0 W% z( q" D! ~- l3 l
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, 0 c+ [1 W/ z2 ]2 D3 `6 {
adLockUnspecified, adCmdText );' K4 A5 S: { S( g5 d
: j/ i! @3 [: D5 @
或者
, M5 n/ v3 [- t3 J" ~ ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
; w- F) c4 Q# Z Z$ V0 ?3 A* i return ptrRS;
: d9 ?9 j5 d; d g5 S E4 _* u }
* }$ n& ^& _0 p catch( _com_error & a_pComError )
: J1 p$ y) \& G# b {
6 I: l. R* n s& ^4 n$ ^ D1 y- v h: b ….// 错误处理
; D1 p; k3 H o. @5 y$ z7 ] return NULL;
1 D- I3 z/ _& t+ f. a }3 @+ @7 o: b2 k
}1 d% O/ T8 [ H' W2 I# ~
- `2 v8 A. O3 M0 m
0 z/ R/ E& _6 A, s& y7 x8 W4 ^5.通过数据集(recordset)得到列的名称/ q- b( ^) _, }8 Q* j$ q
: F( X- |8 P2 G9 d/ V" OHRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象5 C8 C# F+ ^; K
char strColNames[][255],: @. h9 z0 s, t" o: {
DataTypeEnum iColTypes[] )
K; D+ V- j) G- m{+ s! B$ L) a; Q- r/ @, e6 x
try1 a) r* q3 F' ^1 q' B* Q
{ // 参数变量
/ d& \& v+ x* y! T _variant_t l_vaIndex; k& u% p3 I% T, a3 [ }6 U) o
/ ~8 H& o8 z, Z# A$ ]* W l_vaIndex.vt = VT_I2;: O( } i) Z6 u
3 T( C* i9 B2 }% I: p" p K
// COLUMNS总数
* r3 @$ R4 @: } long lColCount;
. {9 s5 W# Z1 T! n& J8 u+ y. P" S7 n- j% U! G
lColCount = ptrRs ->Fields->Count;
+ N: m4 \8 u5 @6 V# G7 O9 ^$ d8 B* F }, [, n
// 循环取得列的属性和名称
* O# [& c5 r! f1 S9 M( F for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
# ?( y' ]! G. P! Z' p8 Q3 B {
( k/ {" _. t7 S% R* m( ~ l_vaIndex.iVal = iIndex; // 设置循环索引
, a! b3 C1 T; F9 u, J
0 u8 w0 q7 W( g* W+ P // 取得字段名称# v5 t" ]% u/ t, D& w" a0 A
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name); p6 B# Y+ a) d7 Z7 C3 }
5 F: ]6 W9 u9 i( d2 T5 {% {" w
// 取得字段属性5 y; z7 i8 a1 g* S
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
4 {4 Z0 ]* W- }$ J }
0 x8 m5 G4 e/ o( p3 k return S_OK;! ]* \+ O( E' r. p/ k4 G
}' B$ l" Q. [; I2 `) r4 p$ G
catch( _com_error & a_pComError )7 H4 \ q' }! u W
{) Z$ X3 p( M. `; f0 ^2 Z: C, Z7 Z
…. // 错误处理
; q9 C& T% X9 ?+ y1 h4 K return E_UNEXPECTED;
# C# D5 K+ H% `: [9 k+ M }5 V$ R8 G9 @# J( p9 y u- E
catch(...) T% A0 ?9 G- I# m9 b. P
{0 a# I2 T8 R( ]; p
…. // 错误处理/ c9 E7 f3 M+ t X' e! Z. V
return E_UNEXPECTED;
- U3 E3 w4 J' D- f+ q4 i }! f4 H* C, S, k# G% l9 ^9 E
}
# J2 C) j: V- `! V' C8 {. F2 j! r1 B1 S# E) v+ \" D/ U! n
; R6 }" F$ q! X8 ~6.通过数据集(recordset)得到当前行记录
3 f/ @8 a" @, e5 a+ D8 d' C6 w9 d+ _8 U+ H. c3 |7 f: e, h. y
HRESULT getOneRecord( _RecordsetPtr ptrRs,
0 _' S. m( v, }% I0 e& l3 [; h3 w const long lNoOfColumns,
- \% `( B2 }: L0 b! } _variant_t varValue[] )) F5 `/ w7 Y: ]9 J
{
\6 V0 [" v- e, ?* K! p" p try
3 A3 f& u: K1 Q, n0 J5 {+ H$ g; D6 A {
9 N! F5 w, e3 }; d // 参数变量2 x/ g$ U- Z3 z
_variant_t l_vaIndex; i5 n% k1 k T* e
l_vaIndex.vt = VT_I2;) h7 A- o4 w3 {+ K8 t1 O* R
) u2 D$ U% S2 ]% ~, }) N, a% z- u
// 循环取得列的值
* |; c1 J2 [. ~2 I: y for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )8 v3 D8 V+ C" A* p7 s3 }" G
{
# L2 v) A) c0 G0 w: U l_vaIndex.iVal = lIndex;
+ g( _+ |" x4 z% a; j3 [7 j6 o0 |; i7 s2 S1 \% ]. o( v
// 取得字段值. m1 D6 S) }1 p6 Q0 h. x& d
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;" U: w6 }/ T: O7 c, {' v O9 x
}9 F% q/ q; R C! I' C3 A
return S_OK;6 e+ {% M$ c" K- j- X; t. J
} M- Z) N- l6 O8 m* f( W+ P
catch( _com_error & a_pComError )' H1 _( q, ?5 A. Z
{' V4 c+ h( ^( d3 Q) k
…. // 错误处理% C) t% r$ v6 Z- u3 {
return E_UNEXPECTED;. E% _' z/ I- a* Z
}
}$ y4 T/ k8 | catch(...)
1 s# A7 L8 r, h1 b {
9 w2 H. H) c; ? …. // 错误处理
" T$ e& [8 t& T" f& S return E_UNEXPECTED;( l) A( F4 g' b% p! u
}
|6 G2 }7 p2 \ ]3 B% s}$ z3 I4 X$ Z2 o1 w8 k: D+ x
8 x+ t. {1 s/ t3 a: p: p" ^7 h+ R* [! a3 T
7.出错情况下错误信息的取得% J" i7 y/ W- Z3 q4 t
$ b. E. U; w5 {4 S- o) I
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );8 o1 ~5 T2 G; Y, I
{
- B7 X4 G: X& L' w- X F1 E- Z; }1 s // COM 错误取得; m, F/ J( G& c
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
1 y8 d8 x) y" T5 } char lpComErrorStr512];0 U" S, _4 ?8 i
+ \( i: }" J. Y sprintf( lpComErrorStr512,# K9 o) k! `6 `9 k+ X. f
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",; a6 Z+ F8 S2 ]1 n
pComError.Error(), // 错误编号
, ?% |- O0 ~4 H" r pComError.ErrorMessage(), // 错误信息5 L5 v( \! M! U% O2 |- ]
(LPCSTR) pComError.Source(), // 错误源
' c- b2 w& a, ~. w6 b& H5 x (LPCSTR) pComError.Description() ); // 错误描述2 J/ w" H, }# i: l' B; O* S) L, M
( D8 `4 s8 A z B9 N K6 f+ n // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息, b8 I, o$ a) |
// ADO错误取得4 p2 s! g- J1 W; N. R4 {0 H
8 d0 ]/ l/ o V; b ErrorPtr pErr = NULL;
! o& [4 [3 y3 ?' ?# C4 E; G3 j) x; _1 g if( (ptrConn ->Errors->Count) > 0)
5 e1 o* U3 E1 c/ g7 { {
1 x! k& E; m* y3 y I; t long nCount = ptrConn ->Errors->Count;
" l6 B9 s" h5 E$ V for( long i = 0; i < nCount; i++ )+ T8 N; ]8 f$ w4 `" U
{% g, l* i, `9 k9 p
pErr = a_pConnPtr->Errors->GetItem(i);
: a. l8 H- @/ S" [$ n
2 I- Y3 L; ?2 B* }' p char l_pchErrorString[512];6 w+ ]5 h- A( L' l2 b
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",: g ?/ x6 F1 _7 ?
pErr->Number, // 错误编号
! |* d! A# I8 w4 m' a" M5 ] pErr->Description ); // 错误描述+ `1 s* }* m4 {/ {
}1 `( T" P {4 d. y
} d% R. s8 B0 Q/ L7 m& F5 a5 }
! g; x: Y! q- J6 C
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问& u- [$ P$ c/ R- w9 W6 E' f
// connection 对象取得错误编号和错误信息。 |
|