|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
# J: }* D: {: j8 P1 A, A2 Z* _! q! E7 {) t& E' h
1、 用import导入ADO 的 COM 文件msado15.dll O+ b2 ]1 O* T# Z4 u5 a7 `) j
. O" b2 e1 }* M+ }* o
例如:
3 s. ~, m7 B2 e0 c. b V3 C3 H. N( h6 _. F x- ~
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\9 z* i$ S1 p' Y, h, V
" S; `/ w9 T1 f no_namespace
/ A& x$ r' @: B# W4 @
, `' F. t9 y: `3 Z1 a- n3 z1 Z- G& n$ N6 X
2、COM 使用时初始化. s. ~ J$ d3 Z G: r3 o& ^% f
4 {+ y/ t! k0 v2 q9 {; h
HRESULT ComInit()( m7 O3 O2 s' P! N6 `; b
{ 9 y/ ?7 {, a$ M+ O( f- j
HRESULT hr = S_OK; // 默认返回值2 k% g. K1 K7 c$ b
if FAILED(CoInitialize(NULL)) // COM 初始化调用) ]) [& I# `, m0 y
{+ s/ b; D/ r) b# q; q$ l' d
CoUninitialize();1 w4 {! P7 [9 J- A3 P
hr = E_UNEXPECTED;1 ?3 g0 F0 q8 D$ I7 K7 A( E
}
' Y5 }- G4 w* \. l9 {2 ~ return hr;) f. o1 n. k# h+ C/ |* L
}7 [+ G. [- o. x( C) T& W" @: c
, e4 f3 V% S( ?: l, R
6 D4 |; X9 W: ?# V( x# e3、建立数据库连接" `: o: U/ d" y6 j: B6 b+ G
' F9 `5 t3 o( y% O s$ u
HRESULT ConnectToDB( LPSTR pUserId , // 用户名4 [8 x% d- c4 l
LPSTR pConnString, // 连接字串 - }7 F* I- L& M6 }3 i
LPSTR pUserPassword , // 用户密码
) v6 Y. f! ]4 F# I' { ConnectOptionEnum ConnectOption ) // 连接参数" V7 J9 o5 m/ K4 t1 ]. y
{/ ?5 C$ E f9 x4 h; O
. b' ^& n8 E( l. U+ p3 e6 M, l HRESULT hr = S_OK; // 默认返回值
+ a( E6 K1 w/ W7 O8 K _ConnectionPtr ptrConn; // 定义Connection对象) N, j3 j: O/ F
& o3 X1 B+ O7 N) n# X try
! K7 p1 }( E8 Q7 K/ N4 v8 v) e {
5 l! T$ |$ w( z8 `( z1 R // 创建一个连接实体+ @! {7 c' O# g; c7 a+ i4 R
hr = ptrConn.CreateInstance( __uuidof(Connection) );$ j) H2 X4 k' {# V' F
) S2 h: ?8 [1 H1 w z6 |3 Q4 V // 设定连接等待的最大秒数,默认是15秒8 s+ s/ [& ? o: L& {$ m
ptrConn->ConnectionTimeout = 20& }9 y& G( F' |2 r4 x6 O% a; s2 o
" T' P9 {" e8 {0 Z1 I0 e* j8 u) ] // 打开连接7 M) b" w1 R% o' o: A: P1 i/ Z5 a- w( x
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
' h8 M% O2 ]! t4 ^1 w0 s) R* C! N return hr;
0 S7 f* ?4 n, b4 k) S O5 V+ ? }
: ~+ k$ J* X& z$ `3 s/ q catch( _com_error & pComError ): F2 R' o7 u3 y
{
7 X7 i$ l5 e; v0 {5 n …… // 错误处理
' r9 `( Z/ a& G4 p" T- j return E_UNEXPECTED;
$ q$ v: ~9 S7 w* I4 K }* m5 g: z1 {0 w0 i; f+ c9 y y
}
) l4 j7 M0 a9 d# `% k; \3 b0 L: ]! c2 m4 `8 P
8 _0 x7 X! ?, I5 F1 |$ _$ Q
4.执行一个SQL 查询,得到数据集(recordset)
/ a1 n0 F& m# X6 N7 C
' p6 N2 o7 [. X& ]6 f8 q+ `% v& V_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )' J. _+ h5 L5 H7 d
{- ^0 d; T8 z; Q0 p
try. k8 l" ]# L* k/ p
{) M$ N. V* ]* G7 n V2 A
RecordsetPtr ptrRS; // recordset 对象4 b V! j! F7 o
# x% Y2 W. ~5 J( p3 p& C // 创建recordset 对象实体
3 F! s( Q* g" t* V# | ptrRS.CreateInstance( __uuidof(Recordset) );% o, ]: _% {0 N# I; y! |
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
: Y7 s, ?7 p5 p$ vadLockUnspecified, adCmdText );
2 y5 x- L/ ]! ?7 k4 m: r- n9 f; x. H7 e
2 i# b% `; J$ G+ U' d 或者% x2 U" Z% F6 O, Y$ g% U
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );; I9 G$ s9 l* {( K8 S7 d! {
return ptrRS;8 P! S* E7 G6 X1 p! A$ k- o
}
8 S. B# B/ D" a$ d* O. ~ catch( _com_error & a_pComError )
' j8 G7 q6 L, }; y) E1 ?+ w7 e0 Q {% H+ y: F* t. I: H# M0 |3 |$ p! Q
….// 错误处理
4 A6 D+ l1 K, Q+ k2 K1 R return NULL;
2 g" k2 n4 Q+ I% C- u9 c- @8 q }
+ z" E0 c% Q8 s4 X( B# H( w}
! H& n% \; ^! g0 W8 U
2 d6 M2 S, }8 p* b7 y0 K e6 S; s0 E8 v3 ?3 V2 m9 d$ N8 q
5.通过数据集(recordset)得到列的名称
0 l. i" L/ _& k5 H& r+ m1 x/ X& @0 j& Y5 q W' N2 O' m4 s: {
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象2 I$ D' l9 Y6 q; e' z
char strColNames[][255],1 ], J7 Q7 Q S- q: C! b
DataTypeEnum iColTypes[] )6 P/ |6 V' Y$ z$ D" H
{
9 G+ L* M5 n5 x4 ^5 O" Z( b0 D try
- Y$ P/ B7 S$ S8 L9 ^4 L { // 参数变量
& o Y0 j+ G) V0 m: m7 t _variant_t l_vaIndex;2 z( ^5 G! Q; x X& a. i' }
( G+ j5 }3 p) X l_vaIndex.vt = VT_I2;
4 l3 L B9 E$ n6 W- ?( ^, l, x" A4 h& x Q0 e1 g! x
// COLUMNS总数
1 Z* m- ^1 P" ]. L2 T9 F- _! n long lColCount;
" f. a+ q4 c2 ]4 S
7 O/ ~( P! t/ ?# x lColCount = ptrRs ->Fields->Count;
* K# i# Y9 c8 I& L7 O
4 T& Q" Y! I) Q( r, c8 d // 循环取得列的属性和名称
. Y8 v. C5 i$ ]3 ^/ }4 k for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )3 y$ L! C W9 Z. L; b3 d- w* |
{ S0 r! X; w7 f( I2 t+ \, f) I
l_vaIndex.iVal = iIndex; // 设置循环索引 R; l/ X3 O4 n5 |' p" V9 }
1 Y3 B" i ^8 T/ E+ N% }7 l/ y: l // 取得字段名称5 v7 g$ K& e4 A6 ~, O! |' e
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);" a% ]1 F6 b4 n: J7 ^
. M$ M7 H! S# M" l: z) [
// 取得字段属性( H9 h5 M( y Q5 H4 N: g
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
0 G9 d0 n! s7 D }- S/ v, u! Y5 ?0 b' A
return S_OK;
& U5 [" P" D0 M5 s6 P" @8 T }2 }7 c9 w" L {9 L H
catch( _com_error & a_pComError )
% v- s' T: E6 _: e: F {3 H3 H+ k; [* D8 J
…. // 错误处理
# |* O7 O5 S& ~5 x: n return E_UNEXPECTED;
: T A6 j. ?4 t# b2 c5 T }
) q4 C# a3 o& u catch(...)
: ]. l3 \1 j2 u4 ]$ ^! o1 H {# P2 J7 N; F8 F8 n
…. // 错误处理5 Y H0 k9 A( C( B; D
return E_UNEXPECTED;, |1 b2 n3 y5 X! t5 E) q" V+ |, }' M" `
}
- D3 }9 v7 g6 z/ o$ l! _}& v4 g4 o! R" O& O4 Q9 u4 Y7 W
6 c. [8 j8 a: T
! t6 ^& o( E0 J( w6.通过数据集(recordset)得到当前行记录2 k. z; @$ f( v# n( `
' @" Z8 j4 C' k1 V! b NHRESULT getOneRecord( _RecordsetPtr ptrRs,
2 S8 Y$ h Q; _0 s+ R const long lNoOfColumns,6 B. n4 Q9 k. O) B5 ^
_variant_t varValue[] )
# M9 U$ Y* K8 ], _: y& G{8 s% M# { T; [3 i! N
try
3 M, l$ ]8 U b {
7 P. ^% h8 A0 R2 d# W0 V7 n // 参数变量
$ \+ B6 n+ T- Z! F _variant_t l_vaIndex;
& ]. `2 |% |: Y& F7 o1 e l_vaIndex.vt = VT_I2;0 b/ _9 e8 M& m" C0 T2 ^% k6 s; k& j
. B/ r5 G1 P- f4 Y( _
// 循环取得列的值
/ L. f+ E& P0 p4 r3 w. m" E for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )8 X; Y% n- p7 ]
{
3 c. E1 U- f8 l& ` l_vaIndex.iVal = lIndex;$ r4 B7 |2 z* b. p
: N3 a5 |. ]8 W
// 取得字段值
V# o: J2 o- I varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
/ l& V. d! q% ~. x; P' k2 i: { }1 O' l/ L, A; y5 z! J
return S_OK;: R; I; t4 Z" Y/ S; n* c# U j$ }
}
. Y! P: z' b+ L# v: u catch( _com_error & a_pComError )
# [" s( Q+ t5 o, o$ H, L& c {
, x7 s1 o9 {- N; v: }6 A' }$ U …. // 错误处理
1 ]! `9 P& H6 S4 F2 y- {7 T' T: Z C return E_UNEXPECTED;
" L# v8 f# S5 A& b3 K }% J! M6 i; \) Q& C1 r$ J8 z
catch(...)4 N' \2 d4 {0 u
{
+ ]( u- a% r, k }( r/ ^" i …. // 错误处理3 r/ r; k9 ?7 L- C7 _7 G
return E_UNEXPECTED;
7 W8 a: M* q) M. p }- _$ `# q! J/ c% t
}, s4 ~4 t# o n+ R3 F$ \
1 u+ Y5 Z- e" N5 P! I5 |& ]2 A6 p6 X/ K8 `. r; f% t2 }
7.出错情况下错误信息的取得, E6 g2 n! F. t* t; o6 p/ m! R
9 i( {/ y3 I! n$ M, r1 Q
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );9 u: q/ z1 T; I3 k! j: n& a
{/ N2 g1 f" q5 v1 l+ L. C3 z
// COM 错误取得
# ]: V, x: p; s$ y$ v% @% j // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
% Q5 |* O- h2 J! U; S char lpComErrorStr512];* i$ N a8 ]( N2 d- |) J
" W$ Q7 O1 i, G) Q+ Q2 U' B
sprintf( lpComErrorStr512,
; p0 w% T/ F4 ^$ e- c7 T1 S "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",
) N7 {& u. Z4 G! ]& ?7 n pComError.Error(), // 错误编号
, d" X6 E, R8 O `# e( E: h& e. Y pComError.ErrorMessage(), // 错误信息* b0 n0 _1 j. D: o$ L4 t4 A
(LPCSTR) pComError.Source(), // 错误源
9 O) V5 B+ a; z$ Y# y4 l (LPCSTR) pComError.Description() ); // 错误描述
% `6 O% {+ e. E! U- J5 y. e. d) P1 m. b) ~- q9 ]; i: p8 J
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
& f: { v4 K# w8 E! U // ADO错误取得
8 e" G' n0 z- q6 K7 [( s2 `. _5 Y( X7 r% | P n
ErrorPtr pErr = NULL;! ~0 t( `1 W$ T' W) \" T
if( (ptrConn ->Errors->Count) > 0): V2 ?, E; ~0 G7 o7 v
{" B( C6 e8 j7 q1 d5 o6 H4 J
long nCount = ptrConn ->Errors->Count;' j+ S4 |+ Z* V, `
for( long i = 0; i < nCount; i++ )
3 o6 G- ?5 J5 y4 F8 C b% c/ D {, J x4 A; e* I' P
pErr = a_pConnPtr->Errors->GetItem(i);; @" i/ G; n& X, `! t
5 m! O* j- w' b- |) f8 @* S! Y" S3 P6 H
char l_pchErrorString[512];$ c, a% Q+ o$ U% a, B
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
6 _$ A1 P/ a5 Q {* k pErr->Number, // 错误编号
. \/ s0 F: U, i, `5 c$ J& j: J pErr->Description ); // 错误描述
/ C% f: E: o* H* R }- o0 O( A$ A/ {
}
" f9 t6 X4 v7 p9 ~$ M4 B4 e: S3 T+ g. G" ]" q
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
7 S8 Y3 {* k7 u5 D7 _" F+ ^% n // connection 对象取得错误编号和错误信息。 |
|