|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。0 H, A* q. L6 d- J: C. M
) M1 Z( r, {- r8 p; w% e5 a1、 用import导入ADO 的 COM 文件msado15.dll1 e( Y8 W* K. K, [5 u5 F# E0 M
& F4 Z, N" B" g+ n
例如:
U8 M. j( U' M5 N- k( }3 |; B! N3 ?2 {! m7 b
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
: e- a% m9 ^# B6 X
( z; N: t! w1 ~6 ~ no_namespace
) ^, T0 P7 N2 Y3 h9 F5 P% W6 {* n! P0 H! d
9 [# M) y1 ^) w p3 K2、COM 使用时初始化6 g8 r5 B% I4 |5 X" ]
% d0 E- ?3 U/ i: _2 GHRESULT ComInit()
, K" ]/ I/ N6 z6 w{
% N& S1 d+ [0 d c HRESULT hr = S_OK; // 默认返回值+ @1 Q; r6 a8 b: B- ]! u& ]
if FAILED(CoInitialize(NULL)) // COM 初始化调用1 j5 D s) p5 h( R) W0 `2 \1 [
{
& M; u# ?6 P7 J% |8 ^) o. p2 b CoUninitialize();) z# w) C" S1 n. m$ h0 w
hr = E_UNEXPECTED;
" H0 D0 \+ e& h }
& P/ Z! X0 r* G return hr;
* ?6 f' X( t8 c! I}
+ [7 d6 ? T" y: D2 @7 d: q
, D% v8 |3 \- R- F0 V1 z; {( N7 |8 Q- j% C# Q, n+ B
3、建立数据库连接/ ]1 s0 c6 g, R
' ]- T( T" d! E3 O
HRESULT ConnectToDB( LPSTR pUserId , // 用户名9 E; Z3 Q% c, N5 j
LPSTR pConnString, // 连接字串
& C+ |! O r' v0 `; q5 k# K R! |. q) A LPSTR pUserPassword , // 用户密码$ ]' G& s/ c; p4 Q9 C) F
ConnectOptionEnum ConnectOption ) // 连接参数
?3 e) c* }3 a4 b) ]{
" ?* v0 A! i2 h% z: \+ Y( Q; ^; P! Y2 ^
HRESULT hr = S_OK; // 默认返回值) u4 b a/ u6 L" D8 x* u
_ConnectionPtr ptrConn; // 定义Connection对象
; x7 ~" `* k. {( s+ z+ M; |7 V4 g0 ?9 F
try
" F4 ?( Q4 o% {4 |; N% O! a( Y {
# {& A/ F( ]: r // 创建一个连接实体
" n( h j8 T! T6 m( c$ y1 X hr = ptrConn.CreateInstance( __uuidof(Connection) );
F7 }! F7 x: [1 L3 k3 o% h8 s% j
. k+ P- q- d v, d // 设定连接等待的最大秒数,默认是15秒5 d2 I) J/ |# l2 \" y
ptrConn->ConnectionTimeout = 20
/ z1 |7 I2 R* p& e
0 r8 ]3 i0 J; W/ q // 打开连接
1 T( ~; l" w7 K b$ ~2 t hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
, I: z- ] D3 b+ e7 f: p+ F. ?9 Y1 m return hr;
- V- U0 a: u! y2 a' X: { }# a3 i: {1 e: @' m5 e" I
catch( _com_error & pComError )
* }# O' @5 \+ ~ {
2 V" ~7 M* Z8 {% I3 @ …… // 错误处理
% h5 Y# ?3 r. R2 U return E_UNEXPECTED;
5 P. N; S9 b; [8 f5 p6 y: } }
. z6 _! p# b1 O- u}
) Q; B- u+ ^9 a( @0 {" j9 Z% e$ i6 d- ^1 n
9 B# O4 ~( {* j% M
4.执行一个SQL 查询,得到数据集(recordset)
1 _' l5 W0 s: V6 j# z, z$ L
4 I2 R& ~ l3 R% q" U# W! J_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
5 e- v; }* B3 Y/ A. E* S1 b{) z8 Y6 y7 x, g0 f: Z7 B3 N" |
try( u9 ?: K0 v' W
{
, u- H2 ?; w5 s& Y RecordsetPtr ptrRS; // recordset 对象$ _! z/ _6 ^' [3 @" q
" V! k Z& f* c, \* r% ] // 创建recordset 对象实体
3 L0 y# G1 c+ p1 X6 h, x: G$ ]& S ptrRS.CreateInstance( __uuidof(Recordset) );
/ {* W/ q9 e- Y& } ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
: i( d* L' _* b! KadLockUnspecified, adCmdText );/ O6 o7 j- q5 E5 n9 m
/ y+ G3 q9 B4 L 或者
4 W: p( D8 I& W0 T ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );& f' |& T1 q' @- e M. J3 { v
return ptrRS;
; X& P3 ~% r5 z }' E' L* O; H2 L2 Q+ G
catch( _com_error & a_pComError )
7 F) N# X% h: Y+ j4 c/ ] {/ `8 n2 o( ~4 {& U, s5 Z9 f
….// 错误处理
s9 m% w& {; d2 n w return NULL;
! z, f2 t' E3 Z }1 Z1 `% b& r2 p/ N% w& X
}4 A/ d1 B) j" D( ?
4 a. o) N, n4 b% f1 c* K. a" \6 P9 V- d, \% X2 a D6 Z
5.通过数据集(recordset)得到列的名称
- H: B0 I$ N* t4 }; Z8 F6 b2 K) f- ~$ K
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象1 i- L l5 `3 T: x
char strColNames[][255],
+ I- ]# ~5 W* Z" B8 S DataTypeEnum iColTypes[] )* L0 H- o& A% [' C0 p ~
{9 _& P9 g/ X. i! J- b! q
try
; P8 u5 P `% Z+ z0 ?* V! x: m { // 参数变量0 \$ O* S5 |! P, D3 q
_variant_t l_vaIndex;
# o3 p! ^9 T) q& y
2 b ~7 s1 \- c4 T- t; g2 C l_vaIndex.vt = VT_I2;- ?- B7 L- b* E1 f
0 r# ]7 R+ T& d
// COLUMNS总数
4 b! O! K$ _8 [7 Q3 d) `/ F7 @" d long lColCount;; }% w/ z3 { E, [
& L) o7 h4 l# e% w lColCount = ptrRs ->Fields->Count;
* |) n( @. Q) |) ]( w# r# ] O) S- F& S3 o3 F/ l @8 B0 D
// 循环取得列的属性和名称, Z8 _$ K% V# ]+ V( v Z
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
8 }4 N" A/ L+ e$ @% |: S {" F2 M! K/ Z( F' E( K( O, i" X: h
l_vaIndex.iVal = iIndex; // 设置循环索引& P+ n$ }+ Q2 \) ^
* n8 R$ c" R: M1 }8 d // 取得字段名称
; B; W+ c$ P3 y2 d0 d0 M; A sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);2 a5 }! U/ M( c2 L3 f
. [! @' {4 d: n/ d
// 取得字段属性
; S3 c& V- l9 j iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
3 D- P/ M: F! w( b }$ l( U3 J- _/ e8 I9 [! ^& a
return S_OK;
5 y4 [; f k* C H- Y2 T }
/ n6 R& c! x3 w9 v# B' A9 ^1 _ catch( _com_error & a_pComError )' S' g. e- ?# y7 Z* c; G6 h
{
1 I; }5 w' ]2 b3 b z …. // 错误处理5 y) C+ I! q$ w! f, A n( B n
return E_UNEXPECTED;# w! _; ^) j, \
}. u( h' q7 ?& E! u# ~* y+ Q- W% {7 e
catch(...)
) d2 v. u" L- `7 z {6 b- ]& l* t" S0 K- Y
…. // 错误处理
( i- q* m+ w' [' @) a* n0 \/ A return E_UNEXPECTED;
, N0 ^' I1 j% s+ s# s }/ O/ M+ L( g/ ]" f* } g+ `) A, Q |
}* T! C4 f' f9 J* X# z# N4 \3 h
9 |$ |4 h2 ^9 V1 P6 n% u1 J+ N- d8 @" [. `5 m4 W
6.通过数据集(recordset)得到当前行记录% L5 j3 Q" C( o c d8 q
; ]: E1 q6 f' h- k( J. u, F
HRESULT getOneRecord( _RecordsetPtr ptrRs,, B1 o/ a8 Z* e7 G0 f
const long lNoOfColumns,
2 F% X) E0 O; e( M z$ h) O0 V _variant_t varValue[] )
* K& s6 v. f c5 V3 V{
6 \2 c( {% t# k4 u: V try
, X5 H" o$ z I0 T% D' m, U {
2 Y( o# B3 f6 w& z // 参数变量
6 n) J1 R9 y ^8 g, C _variant_t l_vaIndex;
) k/ u: H, x6 v, Q8 L l_vaIndex.vt = VT_I2;9 t# ]3 A) x/ m
. v: K1 ?( D! D: S8 b // 循环取得列的值4 {' e; l. z. Z% u# p1 u
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
. A# h$ d+ _- }/ H' e4 S8 z: `: A {
6 Y8 l& K$ P; W/ G; h l_vaIndex.iVal = lIndex;
- }- O* z2 e/ t7 w! \$ q+ z1 |. W* k+ x U5 ~: _: ]& a
// 取得字段值
+ L+ [! c2 ~# F0 @3 s3 p5 U) x V varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;" \3 s1 d. S' t4 ?& H2 `5 {# N, N
}3 D n( K, M0 i$ U
return S_OK;8 J q3 J3 K/ N1 m5 Y3 Z! k% Z9 f
}
- ^) b7 f2 l+ A8 _. b" L catch( _com_error & a_pComError )) k; h6 h9 A0 ~! U3 F9 t
{
/ s+ A8 r8 M+ x9 e2 i3 [. S8 \& M …. // 错误处理: V" w7 j) y+ T4 j" \* p
return E_UNEXPECTED;0 V# |/ c$ o m9 B/ u
}
4 a' X$ e. ~& Y) { catch(...)
1 h" g+ i) \; B3 w2 | {0 v) |0 g3 S5 z* m5 Q
…. // 错误处理% w( |0 M. @% T- s3 ~6 r
return E_UNEXPECTED;. ?7 Y! d8 t j8 c* \5 s4 g
}. p: O9 t3 O' S0 Y
}9 N) W2 u; D% s7 f1 _/ s
) J6 p' x/ D/ K& Z; w# e6 r& `) G6 _) P0 J
7.出错情况下错误信息的取得: ^9 w: }9 X3 A% m9 B
0 v( m! J, d' w; N: Hvoid ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
9 D4 W& m% q8 u% b( M{
$ A Q# X% H( ]0 h. S // COM 错误取得
/ [- F: Y2 I" O4 H1 L$ j. j // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
5 P) g' Y! m2 q8 w4 F, ]; q char lpComErrorStr512];6 ]( W f _/ _1 Z6 [1 b
6 c' L4 g, Z+ {; }+ R
sprintf( lpComErrorStr512,1 u9 i. v7 i2 \/ l2 p
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",0 Q6 m- L9 \( q D7 M1 h% ]% |
pComError.Error(), // 错误编号
$ e+ F$ B5 h; g. f7 P8 _' U pComError.ErrorMessage(), // 错误信息
8 A: F- R, D, G3 d; \ (LPCSTR) pComError.Source(), // 错误源9 L3 Q9 z, G! q% b, B
(LPCSTR) pComError.Description() ); // 错误描述
! t2 i# M2 d# u9 _% c$ u" ^4 F& ^6 w& X7 z/ s: q$ `. f3 y
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息7 [. N$ X: w% W* g' E/ |
// ADO错误取得/ J$ \( {3 S0 C
; K! V: C& f1 I' ^$ A) x0 R ErrorPtr pErr = NULL;. l2 p3 ?/ t' s0 p( g7 C( |9 N/ O
if( (ptrConn ->Errors->Count) > 0), q. x% `. D3 H& ~# v, m) a0 w
{0 @% y2 ^0 o- b( |. c
long nCount = ptrConn ->Errors->Count;
% L$ m% O7 h/ ~! H. A for( long i = 0; i < nCount; i++ )
8 m' D8 c6 Z5 Z' p4 K9 Z8 r( x {
2 ]3 G z6 l4 o# C( N: j pErr = a_pConnPtr->Errors->GetItem(i);
! ?, _; h( s9 S, T' z' ^: z5 m4 P. S- }, P* Y0 \7 I
char l_pchErrorString[512];
8 q% a% L9 [8 u) }' n: j# M, F5 Q sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",! Z- Z7 z. |% ]
pErr->Number, // 错误编号
o3 r d1 Z/ N9 D* B9 n pErr->Description ); // 错误描述
" e0 h$ \' w3 w. e' _ }4 m- U" R/ J( ~/ _$ W+ d
}& j2 ~# G* o! ~
# q& P* c) G1 u7 J* K" E // ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问" B( b/ q: ^# w- e4 j& i9 m
// connection 对象取得错误编号和错误信息。 |
|