|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。- _( x* e+ [- Q% y
! f& W* x' t- z1 `2 ]* Q0 B& S' @" C1、 用import导入ADO 的 COM 文件msado15.dll
8 D6 l1 F/ n& x; \0 I* L' J M$ h) |4 z
例如:. Q6 a3 l1 t8 L1 u7 D, z5 P7 I, P+ o
- q; _( z/ p! g7 m7 n0 ?2 g D #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
4 d x! o# `. q, s& ^, t3 L% _, Z: E$ f% a C
no_namespace* F# x; y. f2 b1 ?$ k" B
$ I2 p3 A: @7 l* ~+ D
9 L+ R: b6 U7 }6 g3 J
2、COM 使用时初始化
! M" I5 l, V7 X4 L# P+ l$ k1 ]* Y. D4 `' @
HRESULT ComInit()# A0 C# {2 V: u+ D3 z
{ . W/ q2 ^5 [. y! M6 f
HRESULT hr = S_OK; // 默认返回值) g# P4 k4 _7 |+ Q
if FAILED(CoInitialize(NULL)) // COM 初始化调用% A _* f" J8 s1 C; L
{$ R3 i& P; f3 S2 ^; V' }9 g2 I
CoUninitialize();6 k& ~. U: l' {
hr = E_UNEXPECTED;' C- o2 x* `$ ?
}' }3 ?4 }/ S% j- o, P. s
return hr;+ f" z( e5 }! F# I
} R! c0 v; }( @" b4 V/ H* k7 h
& ]- p- M" `9 O, u
$ ?0 v3 l8 w6 }) y3、建立数据库连接8 n. l& J }, J1 w1 ]% ` Y5 U3 i
7 \8 z, V( p/ m# ?: Q
HRESULT ConnectToDB( LPSTR pUserId , // 用户名
# [3 z4 t$ F7 S9 C3 D+ V LPSTR pConnString, // 连接字串 & y& n% K V6 r
LPSTR pUserPassword , // 用户密码6 k4 g0 f! Z1 a* S% F- o E
ConnectOptionEnum ConnectOption ) // 连接参数
2 q ?4 k# i3 w; h{
5 Q7 y7 N( G8 k. h [; ^- Z, m6 u( p; U4 y' y q c
HRESULT hr = S_OK; // 默认返回值
: B+ ^: J+ W- B _ConnectionPtr ptrConn; // 定义Connection对象
1 F# `/ `9 F5 F a
% e3 w: M. ^( b' B, A% S try
- e! w f. x. P) i- D$ N {8 V5 t; _ j# x/ K, a3 E
// 创建一个连接实体
4 u+ [* O/ H7 w hr = ptrConn.CreateInstance( __uuidof(Connection) );7 n7 H& d% b) H* O
# l2 q# [$ |. {# O* L // 设定连接等待的最大秒数,默认是15秒
" h- L6 S; Y; j ptrConn->ConnectionTimeout = 20: Y/ ~* t7 G C; p' c2 ~
1 ?. c+ l$ {7 v% M+ c1 X% u1 ^
// 打开连接
0 H6 H3 v: b& A8 g# N hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );7 L- U6 {) W. T6 o% Y' C
return hr; v N) ?. y+ h
}
% y. f P5 |6 f# c catch( _com_error & pComError )
3 J6 q' p' c2 u6 B {
2 T) Z& L2 D& d0 J+ B/ _! q1 H* w7 A1 b …… // 错误处理/ `! r! W3 J |$ p; T# V7 x; c6 G
return E_UNEXPECTED;) t7 s1 F$ G( e) C% y f+ n0 I
}
, I* `1 J9 S/ ^} j8 h9 r0 @- `
; R' T7 _5 H! g! Z$ z
% a5 q7 X/ G* a8 y; Y5 U4.执行一个SQL 查询,得到数据集(recordset)
; `- p9 }' r# X4 O, z- S& }/ N) T$ W, Y4 f+ K2 j
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
/ h" L1 [9 P0 d* ~4 i3 k# V- Q{
; o3 r, r# u1 W( \, y* |' D try
8 M5 ~! ^# Q3 n8 a5 X" r7 F( @ {
5 W! t4 l" u X. J' b( V RecordsetPtr ptrRS; // recordset 对象) G" V( }5 @# ^) i; m3 w" t
0 m+ f& e. T6 X( z9 s4 S3 o6 b9 Z1 t // 创建recordset 对象实体
& J. H3 h" N( b0 z& d6 d ptrRS.CreateInstance( __uuidof(Recordset) );- |2 ^9 l- n* I6 m' H2 ]
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, 0 ?. g2 y$ d$ m6 P5 p
adLockUnspecified, adCmdText );( J3 ]& _# ^& o: R9 O
$ n, o4 N, S9 H& u; U4 o$ a 或者, R$ k( Q9 o" x
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
8 X& `3 L( g, e! m return ptrRS;
- M; n( Q5 ~7 f+ M- e1 S }
; Q) a+ O( O/ O catch( _com_error & a_pComError )
, ]6 W) X8 Z" }- B. h: B {% M4 T6 z& T1 C
….// 错误处理
+ X9 l. t( I- N% M6 E! W- a return NULL;
1 M9 Y. |' w) Z }
L( ^- F6 M4 _ V! X4 D}
$ K' Q. j$ D8 n$ F7 \: C" R& y; Q. ?& Q0 @6 y; }1 K
( x, i, d: D' w R2 O5.通过数据集(recordset)得到列的名称7 U& F0 }8 P% l( n% Z
5 z0 _: m2 Z& b
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
4 G! f4 G/ z6 b7 v4 P1 c" J+ c char strColNames[][255],
, i& }5 I' M: M% W3 H; Z1 h! J DataTypeEnum iColTypes[] )! |. }. r8 D- o G
{
: V6 E" N3 F# u% d try; r* [/ U& S$ u3 c
{ // 参数变量
. c* z$ r9 _1 ]6 r& j' P _variant_t l_vaIndex;5 t0 I( a# u1 U1 o. I1 F# T2 s
2 g( @) l; Y& M
l_vaIndex.vt = VT_I2;6 E' n: Q, k( E. O4 i ~. r
- g/ A7 r V9 o* _& }) Y // COLUMNS总数2 P( K- t, |6 f# |: Y
long lColCount;$ _" b* \/ M/ K W$ p& w( D
8 w8 |3 V/ ^( T- }, ~ lColCount = ptrRs ->Fields->Count;
, ^; w2 `6 F5 Q' k9 b0 ~4 j2 {5 }! [, V& g W M4 W& a/ [1 g# i
// 循环取得列的属性和名称
- Y. C4 k$ v0 w! |$ m for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
3 Y" ~8 J/ u7 |) Y* H {! I) z+ R1 j! h( ?) y* ~
l_vaIndex.iVal = iIndex; // 设置循环索引
# T1 Q0 m9 _, i: q/ k3 v# u' T7 ]" R) {0 i% @8 p
// 取得字段名称% e3 v9 J R& X0 ~0 T
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);6 }! o# L# ^3 j/ |+ f: X
$ b0 o5 w$ I$ C$ p9 ~" o // 取得字段属性
4 ?( {$ T/ E( N) `0 Y iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;. a* A5 B7 q }7 ~* M0 R% `# `/ B
}
# `/ z4 W/ \5 o' Z0 k2 z( Y: ^ return S_OK;
2 }! A0 u! J; ~: ^- N; r1 m3 T }3 M; Q7 E2 o3 H7 w7 e4 A' L
catch( _com_error & a_pComError )
) S" h- `/ A0 {9 U5 N2 o {1 V8 ~! Q7 O4 J) g7 ~
…. // 错误处理; a1 f+ X( L" x
return E_UNEXPECTED;6 ?. B; c7 u8 k, M
}& ^$ H M, l) `; T8 e: v, D
catch(...)
: m4 q; N; S- w. _ {
, Y6 k4 P v( k; q% ~& E …. // 错误处理4 L: T$ d7 b6 Q" f0 L# X
return E_UNEXPECTED;
( k- A/ v R K2 f7 ]7 n, p* F }) u9 c0 G2 V9 g: a8 I
}1 G1 e- `' Y3 R' U' |
1 Q0 M7 P! g7 j3 {1 K4 q, b. v( y% z e5 P( E5 j- m0 `. \9 L
6.通过数据集(recordset)得到当前行记录9 o4 k% U0 x# M0 d8 c# C; R
, |& x$ v9 p- p3 nHRESULT getOneRecord( _RecordsetPtr ptrRs,3 p9 n3 f3 w2 S* ?- s5 D& l
const long lNoOfColumns,
# C' m% k5 T% i _variant_t varValue[] )$ _) a) ^- @ ]8 L5 ~
{6 x: s) Y8 R. m. A# N& o
try! ~* G, c' T- [2 ~3 s. `! _
{. O$ h% P" H7 ]* a
// 参数变量( G9 C" h9 ~0 J! ^! `
_variant_t l_vaIndex;
" V3 d! f" [9 C& y6 H" T s6 X l_vaIndex.vt = VT_I2;
: J0 w. O- W' ^ Z# w; i* q0 C3 `6 Z _ e$ x% D
// 循环取得列的值
: o0 \7 E6 _. R8 b+ ]3 E! J2 ` for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
! D& S; z3 F/ l4 ~$ H {
1 u, L& a% t5 |% I) \! { l_vaIndex.iVal = lIndex;- r6 ^: r, R u: p' Q- s
- q2 d8 ^) N7 q4 J, _2 S
// 取得字段值
( y7 j1 R' c" y% G- b( M V% x varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;% y5 z) |* @% Z3 e. E! N' o
}
1 b g/ H8 j6 h- @ return S_OK;' Y c% a, ~, M. o) i' g
}7 F1 L0 J2 j* T- i) t& }/ i; U
catch( _com_error & a_pComError )
* e& b5 C( _$ p* }& Q5 B4 y {
$ j) j2 E0 Y) o# ~, n …. // 错误处理
: Y" F- J& j& b3 [& w return E_UNEXPECTED;
6 f- g+ b4 ^! v3 o }& w# I. ^! i$ i; D
catch(...)9 ]. ~1 @" M, v
{( f' U6 Q6 C6 l* C
…. // 错误处理5 E* S4 ]- Y; e; K2 X- ?8 o$ c
return E_UNEXPECTED;
8 ?. [1 e! k9 C5 n }7 X3 L. u6 s. ]) E
}
. ?; H: x ]- [7 L. D7 ^0 m6 V1 a5 a M3 \
$ _& Y$ Y: b, c" q7 r7.出错情况下错误信息的取得
$ |9 o) m% I# ?- M8 W! F) P$ K- k' r! O+ L$ ?
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );1 r v! c) B) `! [( R( h
{9 ?+ I- j) \$ S- D5 X* i8 Q
// COM 错误取得
9 [4 W5 B, c4 Q0 h // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
. W# k' g) O, T" s/ Z char lpComErrorStr512];/ ^% w; e1 P9 U$ D/ Q
; f' m {+ ?/ j( ^$ S sprintf( lpComErrorStr512,
$ m5 u3 q; Y5 _. w "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",7 @, u( P9 q4 l) d
pComError.Error(), // 错误编号6 _+ j, Q. x; T. z
pComError.ErrorMessage(), // 错误信息
0 c% u+ H7 o1 l (LPCSTR) pComError.Source(), // 错误源4 L7 T/ W: N: E: U
(LPCSTR) pComError.Description() ); // 错误描述3 J5 @9 a8 g" `2 H
- X8 x+ d/ Y2 C! [, q, J; H1 I
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息* o; x' a/ v! k2 E
// ADO错误取得! k U/ o6 i3 |4 c% _& U
: v1 w& @4 L2 |$ H! {" c0 ?; | b0 z ErrorPtr pErr = NULL;) Q, Q5 H" p7 E. n9 k% c
if( (ptrConn ->Errors->Count) > 0): m B% u8 }* }! J) O
{0 @. j, |' B$ G5 E% ]' [: }& L7 T/ A
long nCount = ptrConn ->Errors->Count;
7 \& k1 |' O# n- s# ` for( long i = 0; i < nCount; i++ )- e- ?# p3 C! a9 x& A. d9 d/ `
{$ W O- C4 d+ P5 T" e5 ]4 v4 j
pErr = a_pConnPtr->Errors->GetItem(i);
/ l7 Y! |# _( }4 x- x$ `
' Z& n/ |! w4 b" g$ O char l_pchErrorString[512];
) ?6 ~$ ?1 ~3 r- w, f% o' L sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
: K- R1 ~( o0 R: [; a. [- c pErr->Number, // 错误编号& o0 C! N+ E, p1 b9 [( O
pErr->Description ); // 错误描述
* h2 s$ k0 `* T4 j- b }0 h5 C9 @) ~ L0 x8 k( R u
}
7 l$ }# h! X% ?+ \7 e
* p4 ?3 g ^& m // ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
7 K4 g& y4 K! {" D* y4 v // connection 对象取得错误编号和错误信息。 |
|