|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
( q% Z# w+ |2 k" Q Y2 m: ]+ @) u1 I+ _5 Q% g+ Q8 R9 @6 `
1、 用import导入ADO 的 COM 文件msado15.dll
$ \; i* n8 l& W/ ` j/ L/ q+ c. b! J! |3 ^( X
例如:
- N$ z) B$ G/ u1 p% o4 @' Z. v( b: O- ?+ K# A4 [
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\5 J/ g/ G0 p R& z% w4 ?
/ y$ u. E9 M4 G2 v- ` no_namespace5 R0 O: Z6 J3 v3 S
4 P- E& {0 F) z3 I8 }# z* V" b. k2 B" b' N: i5 x
2、COM 使用时初始化
/ o1 b7 B# t c+ J9 P: X8 [& P) W) r
HRESULT ComInit()
: s: n: k/ d3 N; o{ 3 r9 R% I- @6 ~0 Y8 P& L
HRESULT hr = S_OK; // 默认返回值
. c# ^0 h1 Q, L: [. H if FAILED(CoInitialize(NULL)) // COM 初始化调用( I$ n9 E, J5 E
{
0 @: }; l" g3 Q: j L CoUninitialize();* i7 K8 }" O5 P$ I! E
hr = E_UNEXPECTED; E6 K+ z# ], _6 c
}
0 h& e9 e. X+ i3 r* Y8 p0 A5 h return hr;
! _* q/ _% g7 e0 x! }}
7 [' q g2 u, \6 P+ u
8 a5 K- P9 v2 q) m" Q9 Z( L1 ?/ u0 i( O+ B
3、建立数据库连接- V6 M& A3 W: d3 q2 R v
( C- z9 u' M( K/ n+ p5 jHRESULT ConnectToDB( LPSTR pUserId , // 用户名
* Y) o. }: F. R9 ^( h LPSTR pConnString, // 连接字串 |+ ?+ N/ `* r' K# l) E( r1 I
LPSTR pUserPassword , // 用户密码! c# A! v$ r3 x2 ]" V! I+ o W
ConnectOptionEnum ConnectOption ) // 连接参数" E* P1 C" \8 `7 y O0 l
{* E$ p3 d$ d3 r! K; C9 y
1 _7 P# u2 {# h% R& C; _ k HRESULT hr = S_OK; // 默认返回值2 H Z8 T1 y& k+ t! s4 ]9 f! U
_ConnectionPtr ptrConn; // 定义Connection对象
' i& S$ \% @2 e. p2 w; b8 z
, W3 ~6 \6 X0 j% n try+ [/ s* S5 d. R* S
{' Y* w4 d" l& _8 P1 J
// 创建一个连接实体
; h- P/ y* } a" G2 C c hr = ptrConn.CreateInstance( __uuidof(Connection) );
6 n: n: n4 _/ p. d. A! U( F: B# K- S$ o0 o+ t' G& w
// 设定连接等待的最大秒数,默认是15秒6 Z* a/ Q, D1 [
ptrConn->ConnectionTimeout = 20' U: m* f ^9 F. d' H
b! p& o5 X, |$ E( [- H* y // 打开连接
% @% H% O: Z+ D8 Z hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
/ E% ~+ h" }" H return hr;
# R! H. C; Z1 r5 o% N; @3 ~ }
' ]* l% u ?9 A/ ^ catch( _com_error & pComError )
" l1 ~- d! _5 o* A {4 D8 S# W6 I' X( m4 [' o1 t- R" x
…… // 错误处理. y/ r9 L5 S7 \) Z, F. x
return E_UNEXPECTED;% Q$ P- ~/ v+ B' q/ | l
}7 U' U. @9 W& W, O- T
} U0 h6 O0 k0 w- I1 w; q8 _8 L! G3 X @
/ K7 `6 i' }* v# \
7 N0 j1 @* F! |" S
4.执行一个SQL 查询,得到数据集(recordset)! c% r8 v3 t. E+ K+ G
2 y3 U3 ]3 Q5 V) J
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )' z9 P a% M) L9 a1 G; F
{( q% V# m% F, E0 |1 X- q
try' J+ K; z; v3 s9 A( e
{
/ p) a( P0 u$ i$ u RecordsetPtr ptrRS; // recordset 对象; ^0 b, Q/ x0 W
& I# K1 ]" p) O& T$ v7 ]) J // 创建recordset 对象实体
9 y7 X& Y4 r/ J! }( n# L ptrRS.CreateInstance( __uuidof(Recordset) );# x5 {6 ]3 M# f* c+ H+ |7 w. ?* ]
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, * w9 |, R8 ^) G' X+ ^6 K5 o
adLockUnspecified, adCmdText );
# X& Z4 T* s" g
3 X' k. M: A3 j# K4 q' z4 B7 E 或者
' ~- L5 |: o$ h% V: l8 I& j2 D ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
8 C% G$ x- L) K0 [7 H return ptrRS;
/ D8 w! c( A0 |+ _ H5 u& c2 G/ y }/ M0 _( K# z" r1 N# j
catch( _com_error & a_pComError )* J$ d- A; o# Z6 H
{
" H! D* J$ `0 o" h2 q8 x ….// 错误处理4 y5 `# X3 }- Z& ]+ P6 o
return NULL;
+ b0 ?: J# X# N9 G/ p }
# _# H* [( J. @) q* x}
" F; P# @2 X4 v Q( p' g2 S" s. f" t. I+ r8 o1 A3 h
}* _% O7 i6 @: t# {% m2 {% z2 ^5.通过数据集(recordset)得到列的名称1 t" J. z. M" F% j, H
& L1 s! [! P* }! B) P/ z$ j* X
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象4 F5 J3 Q" `0 c/ j R- Y g
char strColNames[][255],. f4 e q( M+ ^8 ]
DataTypeEnum iColTypes[] ). e1 e0 W# y' {# Y* x( m; y8 i L
{
* |5 H U8 Q$ W6 k+ A try
" `7 u" @3 z% d$ t5 Z2 ?8 m# s { // 参数变量, C3 n, X7 C, S4 A* `
_variant_t l_vaIndex;, J5 s0 S$ j2 T2 G: [ i' d
, e e+ \* a' e* `& ]+ Q
l_vaIndex.vt = VT_I2;6 X6 S: Z7 J" {
* ^" ?* C! U" \ // COLUMNS总数
* z' |: V( M4 @ long lColCount;
( ^7 X/ ?. J O' R* w, S: X/ W+ h" H! a' F& M7 V- d4 G1 _3 A
lColCount = ptrRs ->Fields->Count;
2 y: B9 B, A- Q1 j: @' l* z- Y. w) @. W$ A5 W
// 循环取得列的属性和名称
, {. h; L$ {- f) E( s; z O5 D* k for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
2 j3 }# N, Z1 b* @- s h4 Z1 E$ e {
! o8 V0 t( y2 T9 [% d, B+ w3 W: h l_vaIndex.iVal = iIndex; // 设置循环索引
* l7 w* i+ G8 V0 m' ?
/ r! y; `& t0 E; H( g // 取得字段名称
# x! P8 N' w x: ?+ p3 ? sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
! T" z4 t3 I0 I L' ^* q9 p( P( w) [* R# ]
// 取得字段属性* u1 h @2 z" o, b+ U+ s
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;# ^; @: o6 m3 ]) H' j
}: j( h2 b( n8 i$ ?$ U2 [
return S_OK;% K% W/ S( M% y. v
}% P( O# B1 s* k8 T7 I
catch( _com_error & a_pComError )
2 ^5 f6 O8 R- M& d- H; l' i9 @ {4 }+ ^% {1 _7 S, ]% @. h/ H" q
…. // 错误处理
* n2 l- R' f8 w7 z: x return E_UNEXPECTED;: ?2 m; f Z, q, c1 Y
}
) z( x: J; x5 W7 ~' N* ` catch(...)# z! r! D' ~& m5 I7 k' C1 y
{
- ?( }* w/ M+ o$ N7 Q …. // 错误处理
5 ~$ @ g$ \/ Z& y return E_UNEXPECTED;* |8 A. C' L7 u( v' n( U
}- h" T" L; ^& ?: g% p
}
b, S6 U( U: ~8 z# \
& h" g2 q% y& Y8 q. W3 e. h5 n8 |
6.通过数据集(recordset)得到当前行记录8 N z+ X7 z6 {5 a
9 {1 @$ n' `" H! _# E8 j5 Y
HRESULT getOneRecord( _RecordsetPtr ptrRs,
+ _1 a3 ~; x: ?, M( C const long lNoOfColumns," O& v; h5 d- s, R
_variant_t varValue[] )
* y; u* v0 f, a{
. R1 @3 a1 v% W" h% Q try
5 Q+ a" A) A3 C {5 x4 ?2 I' W4 d$ [
// 参数变量! j( e1 p6 ?8 h' O) e6 V
_variant_t l_vaIndex;
( `$ R9 I! `7 w, h l_vaIndex.vt = VT_I2;0 r! M6 R' q" k# K1 G; Z
6 s% B. y( v4 B0 N) P5 X
// 循环取得列的值9 {/ J* j8 [ k0 `: L& |: y! c( S
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
! l# p( h6 M8 Y# @7 K' E% g7 i6 x {
- I' s4 R* J- N3 o) y7 N l_vaIndex.iVal = lIndex;
. Y6 U( A& H- s1 B3 ~3 A* {" B
1 Y1 i$ P6 _, y! I // 取得字段值
8 @$ }" [0 v) w( ^' X8 o varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;; {; |2 u% _( |7 w5 k) X4 z
}
4 I3 y5 v- l: B k" U; X return S_OK;
+ \& ^5 C# g4 H }
& K/ v, O& f8 t catch( _com_error & a_pComError )' o7 ?4 e I3 D- h
{) s( K/ ]" H8 _# ~* W5 h) j5 l7 i
…. // 错误处理
& t1 c' D i9 |' E( p return E_UNEXPECTED;
2 z/ P) y. i4 r& e }
6 ?8 J! O( O; p& o$ q catch(...)% n- t8 K+ W, t' y6 \) A+ `
{
: x8 r) o) {. j' O; x …. // 错误处理+ n+ }1 F9 K6 P5 P/ s1 m9 C, ~* K
return E_UNEXPECTED;
* t3 x9 S" j+ ?3 ]0 l }1 e/ [' L! o$ T6 x4 s7 _( \
}
. `7 U! L4 @0 \& w
0 h9 x; T6 G4 u) Z1 o' y1 R0 J0 V( [9 e3 C' M! T) I: A1 m
7.出错情况下错误信息的取得9 R( A* d' }% v
" N( \& E2 k" l9 f0 Q( L+ T* p& a
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );7 r4 _1 Y' G8 x- z% H$ F
{
' C& a6 j) b5 }2 ~/ \% e // COM 错误取得) D( `9 y7 P4 I3 z9 W2 q+ R
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常9 K) x! p% ^' M, y+ V7 }
char lpComErrorStr512];5 @; ^; V. h5 {0 A k' K0 W3 y1 W
* y" {5 W2 y! n5 A, O
sprintf( lpComErrorStr512,
) @# p1 p$ `9 g0 X! M+ c( f' R, p "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",4 D8 d" z2 b' d9 Y4 h0 K7 r6 f6 j
pComError.Error(), // 错误编号
; { y7 c- ^' T4 g: x: L pComError.ErrorMessage(), // 错误信息# b1 ^+ f2 A; x+ x& A. m5 \! ^
(LPCSTR) pComError.Source(), // 错误源
) K. h* `9 W" w; i: r5 ]% `0 j4 ^4 d (LPCSTR) pComError.Description() ); // 错误描述
! t$ C$ C3 z6 s J* H+ K0 Y, B" Q# s; ^2 a; M* ~1 ?2 k+ E
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
6 u# L9 B5 C' i; u0 U // ADO错误取得
! X7 |# b# I. H5 s- m8 J- s! N; A S$ `/ H/ x0 o9 n, w
ErrorPtr pErr = NULL;- _- q/ R M% I* v3 J
if( (ptrConn ->Errors->Count) > 0)! U- U2 K E' d! w% o+ b
{2 V% m/ b0 q3 D* H+ f; ?
long nCount = ptrConn ->Errors->Count;! w6 Z1 M9 \- C) i; T
for( long i = 0; i < nCount; i++ )
. u% o" \* L8 ^+ p+ e5 w; J {9 N# @$ f% q# j+ M* \
pErr = a_pConnPtr->Errors->GetItem(i);3 @; n' S2 H% V( B
& k6 \5 G' R1 a/ } U% U, c char l_pchErrorString[512];
m# W' |: W! [* G, S. _* J8 C sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
% @& |0 C x/ ?% D pErr->Number, // 错误编号: c! V4 J5 I. d7 Q
pErr->Description ); // 错误描述+ j- r. k5 ]! {" Q3 O( p/ h1 l
}# u# w! P a1 K) H( M3 j* K
}
5 f+ l7 v, d7 M- ]5 r) \* ?' f a
7 e7 z) A2 ]; c1 T4 W+ b // ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
" c& b& o0 m1 S // connection 对象取得错误编号和错误信息。 |
|