|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。/ @ m/ ^8 e9 j3 O) `
0 @( {. H& V" L1、 用import导入ADO 的 COM 文件msado15.dll
1 R" D- n" w( i# A3 P, @& t& X9 e' F1 S$ v$ G) v. W& o; B' d
例如:
% h! X( i# w; o k" R7 ^* f: E7 d4 F0 V! \
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\; ~. I9 K) V( k
4 c( s% q# t' C( K. l# D no_namespace
% g! u7 |* F4 A4 \5 z. W: H# z6 l/ h v
- @2 D$ V# V5 C1 D7 }2 H
2、COM 使用时初始化# y P+ Y! M" Q7 T6 g- @2 ]$ L
- M2 ?' S$ c% u) B; m8 S! n( G, @
HRESULT ComInit()- W) K) F* Z9 f) T' i& S
{
+ w, i5 J& w$ W# o2 @ T$ Y HRESULT hr = S_OK; // 默认返回值
/ W1 B, s1 j1 L/ l4 P if FAILED(CoInitialize(NULL)) // COM 初始化调用) L2 X6 o8 R- \1 K- K+ C
{
3 [, H8 M2 h, ~" U CoUninitialize();/ q# l+ w, m( d
hr = E_UNEXPECTED;
7 n+ V& P( @# @" G* A6 `2 N+ [ }
2 m: E* Z' C6 I+ q return hr;; _/ @0 Q+ W$ T3 h# f5 g
}$ z. m8 _. E7 \! O7 Y! W* Z
2 Z4 |: ]1 }3 H: v+ H
& L% r; Z' u8 Y* b& l3 M3、建立数据库连接
9 n( ]9 b) t9 W- U0 u+ p# d7 }2 v5 Z( H7 v; U( q
HRESULT ConnectToDB( LPSTR pUserId , // 用户名( a- `$ C8 }5 Y& i) r* z5 E: X
LPSTR pConnString, // 连接字串 % i3 C b! _! O
LPSTR pUserPassword , // 用户密码
+ {/ v( f4 u- a ConnectOptionEnum ConnectOption ) // 连接参数; g* a& f8 }' C( m" Y' u; d* W
{1 ~3 M+ o; P* }0 f8 X% N7 Q3 D
. E0 f# r" ?& R
HRESULT hr = S_OK; // 默认返回值# P9 {3 W d4 K& _
_ConnectionPtr ptrConn; // 定义Connection对象
6 N% \$ g0 N9 r+ k$ }
2 Z+ z o% G/ W. F2 Y/ {; c9 u try/ k5 n& P- E% ~
{* Y$ ~2 I( j/ G2 ?" h
// 创建一个连接实体
; |$ l* s: O- |! m5 z/ I hr = ptrConn.CreateInstance( __uuidof(Connection) );
' Z9 t: n8 o+ E$ R; B3 c* d; Y, \$ N: T
// 设定连接等待的最大秒数,默认是15秒4 Y- Y9 [( i7 {- A. C! H+ c6 F1 @! e
ptrConn->ConnectionTimeout = 20
7 L3 n5 Y9 ~( A; }2 [
+ f$ g! P' Y2 p% q8 q, @ r // 打开连接/ X+ ^% U- O: O4 \9 a3 z/ I
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
! y# r8 e( i" b* T5 `4 U$ z, Z return hr;, s7 O3 G; h. g
}
5 H% u0 I/ W$ |* H. }* g6 x catch( _com_error & pComError )
" N0 J$ K X, |! h {
. \0 [9 N: o6 r( |0 q …… // 错误处理
( E) U) [- p. [" }, p' P$ I return E_UNEXPECTED;
. |( I. o- Q5 U. D% H$ [, I7 Z }
! K# [1 R! g* U, e! W& S}
5 d3 r" N7 p ]5 @6 B
) W+ b; i4 Z, d/ [. f4 j- f
- U: x, O3 G$ x4.执行一个SQL 查询,得到数据集(recordset)2 H) s0 @ w( W( M b7 R1 ?# {
+ |2 }8 r5 W2 l4 o) x( ]# M! v7 a+ a_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )1 x$ d l- ?* N( h
{ K) J. h. t; Q) \( R
try
) Q) V8 Y' t7 l# L1 Q& X {
# m8 b9 |4 k- D RecordsetPtr ptrRS; // recordset 对象% l0 K$ M7 |2 |- E3 o
. W) `9 a8 k3 ` // 创建recordset 对象实体
5 a& Z) s) {, E# x3 m ptrRS.CreateInstance( __uuidof(Recordset) );
( b/ a# A" B' m6 y9 n! y ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
J5 S* Y) ^$ L# H0 r C" jadLockUnspecified, adCmdText );
* h+ s' J; S" b! A9 C& ?
7 J! Y4 o- k0 J$ b' x4 c 或者+ a- h q( @+ \
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
" j/ V$ C; z2 U2 b return ptrRS;7 {- b! X5 m) P% m% k6 R$ K: `
}) |' z; o8 h( c/ w: h; i1 k) T
catch( _com_error & a_pComError )
]- j, e5 P" O8 f+ ^- D3 `! i {
/ C7 A" j) T) P, e) i6 f ….// 错误处理) O2 S/ k/ _5 u0 W
return NULL;7 v- f) B- ]. a$ R3 j/ d* I) E
}" T" O# [0 \3 U# r% _5 X$ t
}
7 |5 k( w9 y8 r' `- y0 V& u- Z' | g, H4 m' N0 F
: x; p! p- ]# }% A. [5.通过数据集(recordset)得到列的名称
: Q v1 q/ J3 E4 R9 l/ `2 U- X/ _6 C i" H
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
0 ^$ ]5 D$ W3 q6 [& v6 x, F! t char strColNames[][255],
% X6 V2 b* n8 f, f$ @3 {: d# h DataTypeEnum iColTypes[] )
F4 p$ k8 k3 k) x{7 e2 d i- ^( ^# M# V
try
1 o( ^. C6 v1 F' l { // 参数变量
9 d$ }7 M, T, i8 z7 _ _variant_t l_vaIndex;
- Z% r2 D: U+ Z4 b( Z
: Z8 u K5 b$ I l_vaIndex.vt = VT_I2;, k. [( K# w e; n. B6 K
& c" a0 f! z* y3 B3 R // COLUMNS总数
' p% X( P+ Q5 }. v4 [2 n, ~ long lColCount;
2 K6 u& Y6 S, m
/ J/ [4 V6 i8 {/ u( T$ P. ?: I lColCount = ptrRs ->Fields->Count; c- a+ f; l& i' W7 Z. ?
- h; A! a8 \. i7 y // 循环取得列的属性和名称; F; i, i: k$ ?6 u3 O4 x
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
3 x F: X6 e% G3 L {
# |3 h l) J# S+ B: a l_vaIndex.iVal = iIndex; // 设置循环索引
1 m2 k1 D: v; A6 U, C$ U) D
: @8 q3 O% ?+ H3 }1 Y0 l, B" P // 取得字段名称$ V/ b' N1 e# a; O
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);& H8 F# ~( S7 P# e$ \- ?5 c
4 d/ M- G H2 t6 R$ Z7 ~+ h! V // 取得字段属性' X$ m+ y! O& U3 m7 G
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
* z) _/ o- {& {- G }
9 K2 |/ E2 Z1 v3 b' g# P return S_OK; P Q4 j( N8 h! t3 D( n' P
}1 D9 J4 A# x7 c& z
catch( _com_error & a_pComError )
+ k q5 _* Q& V F4 ^7 W3 c6 z {
+ l: O' D6 c! a9 d6 e( |0 ` …. // 错误处理* x5 b5 v) }# k7 I
return E_UNEXPECTED;: }3 d5 q/ r2 h' _, s3 h
}" N+ C9 N7 r1 y! R7 d
catch(...)
0 _6 ~3 ?0 C6 E& b4 M {
' j: A# A* h2 Y …. // 错误处理6 w( P% ]9 D4 q9 r" K' X" q
return E_UNEXPECTED;2 m7 v. S5 r7 T# R- J k
}" J' x1 j8 v3 t- m
}
8 b9 y0 j0 b1 p$ B/ W9 H( }8 Q5 O M8 u3 p. ~* u
9 ^) t3 i+ R* n, N5 ]+ n2 f6.通过数据集(recordset)得到当前行记录( m' B" ?$ i- Y9 a% x
1 t% n2 U) O' D: L3 ?HRESULT getOneRecord( _RecordsetPtr ptrRs,) _4 I/ M6 Z. x8 M! q m1 D
const long lNoOfColumns,% O. Z5 P% t y* z
_variant_t varValue[] )
v6 V. c; V6 O{
& t% {$ ~1 ]; g* y" X1 X' H try. a, ^/ o' g# m. ~( c8 Q6 v
{& X; M9 i( T# ?' L6 P
// 参数变量' q6 t' n3 D+ J2 [
_variant_t l_vaIndex;
8 [9 h8 A* e7 Z& C$ y9 P l_vaIndex.vt = VT_I2;) U+ o, _! j+ d* g9 m% g! W
, T# m1 p4 N/ t; Y
// 循环取得列的值
9 D. l" T( U; [) ?9 r6 H7 e3 u for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
* @: q4 O- }; v) f { ' E: q/ I- T4 J ?3 [- r
l_vaIndex.iVal = lIndex;# [3 Z5 r. M) y. n9 h
( W/ Y+ t. M( N2 u* L2 g // 取得字段值& v% J$ q# N$ w8 p( k0 W2 N4 y4 f, e
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
4 R6 F, A [- b }
0 K' a6 E. _; l' ]5 h8 K return S_OK;
7 P. Z8 R4 g5 r% P6 I$ _6 G& l }$ p( v6 ?" f$ o4 k
catch( _com_error & a_pComError )
5 Z! m' G. W! [ {$ B& ]* z% N, Y7 k: T W
…. // 错误处理
& H- x: c8 G& D: P; A% c4 D% j return E_UNEXPECTED;# |& G4 m) S) v& j; ~" H
}) W+ j1 \; _- b6 m; P
catch(...): ~2 B$ M. o8 J
{1 c) Y- r' E* d) a0 g# q0 v
…. // 错误处理$ s6 @. f9 O2 i' X4 w# ?6 y
return E_UNEXPECTED;
7 V9 R' |8 J+ n& V: z) |: _ }3 l' T' `1 W8 z, o g
}
, @ K! A/ ~% P7 z$ ~/ B1 R/ P9 s2 `$ a5 b: z; O
Y, e! V/ ]4 k& z( k7.出错情况下错误信息的取得
$ v5 z3 M! L, o/ n% `9 e
! v' F o+ Y. q; pvoid ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );4 K- x5 o6 F% b* \1 X
{7 b# k: o# F; l6 {2 K$ M
// COM 错误取得
! I/ F L% [3 @- V // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常- i x4 ]8 p9 C6 T6 ]
char lpComErrorStr512];
: W3 T6 }2 U2 C9 k2 D5 [; l( t& u F6 l# q5 f
sprintf( lpComErrorStr512,
/ x9 t u0 r$ E- T' a& n "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",) G2 g2 n8 X, M% M) T) X! j/ Q0 \
pComError.Error(), // 错误编号
: `; m2 E* x0 _% Y& t- l% q pComError.ErrorMessage(), // 错误信息! ]9 ~; \* b/ ^3 w
(LPCSTR) pComError.Source(), // 错误源
! E3 Z$ Y6 z* Y' D (LPCSTR) pComError.Description() ); // 错误描述" n! ^8 ^. d9 I
' y C2 v9 A! n: p // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
( ? M* Z8 _; @0 T( S // ADO错误取得+ U$ d ~) U2 e3 o% r3 h9 p
1 _. g2 b, A, D# p- E+ g* [
ErrorPtr pErr = NULL;5 U B0 F6 N6 f
if( (ptrConn ->Errors->Count) > 0)
4 | E( |8 _1 D6 r W {
8 g1 {: Z7 u1 U3 u! u4 g long nCount = ptrConn ->Errors->Count;
; h) [3 m1 g1 M for( long i = 0; i < nCount; i++ )
( o# X9 U1 n N& p5 N" _( M {
# C% a+ x. t' C, ^& `) M- m u pErr = a_pConnPtr->Errors->GetItem(i);
( r8 K- U) w" I! {
4 @$ R0 ]$ q& D: d char l_pchErrorString[512];
, e' n8 a4 \: v9 a+ j9 }) G+ w sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",8 @5 y% r8 ^* G% C' m: r
pErr->Number, // 错误编号
& p! q. Z$ X: R pErr->Description ); // 错误描述
1 p) Y; n- f% }9 q }- f0 R' c: k- U* m2 M$ S3 [
}
, j }6 i. {' h( ^) G- ~) Q
! Q$ P$ D+ g; e" ?# z: G' f // ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问3 v$ e* n3 ^" f {9 x
// connection 对象取得错误编号和错误信息。 |
|