|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
; @# J* d# v0 R2 |7 L
$ h! R% _) N, b# J7 @1、 用import导入ADO 的 COM 文件msado15.dll
& K& d6 e) D/ {$ i/ ]% y2 F1 X' s; @' X) S5 x+ _- u+ ?0 v8 b
例如:' J) ~4 Z( Z4 N( F; ^3 P
$ f1 H. l+ k( w& j
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\$ s: n( _% ^# r6 N. ?. ^9 [
: R) |. }. q% |. `6 W! K& S
no_namespace3 H+ T" i* @5 m
$ N7 ?# Q; y9 Y6 V
; u E% t4 R% [
2、COM 使用时初始化
% m3 @0 ]" e( B0 @- D v+ T+ b+ Q* g
HRESULT ComInit()
+ j( a7 ?1 x7 R" ~' `/ n* H# N{ ! m0 L% q) d0 Y2 j3 d
HRESULT hr = S_OK; // 默认返回值' a. |( z# R" B6 e ~' J& C
if FAILED(CoInitialize(NULL)) // COM 初始化调用
8 }0 Z- H* C. @' B1 L {
U7 F; g; Y- Y CoUninitialize();
. h0 o6 B( K. l. X/ U( N hr = E_UNEXPECTED;5 h, D5 `) z6 V9 H
}
7 ~8 Q) B2 z4 T/ \ return hr;
$ D7 x% p! R' |" K' L}
2 p) e7 |5 e2 K, f$ R
1 d. _# a' }4 i% n7 \/ a
+ k% r8 Y* A9 j8 Z* `: S9 \* b3、建立数据库连接+ O+ J _8 q! j
+ C! T' }) ?( Y& KHRESULT ConnectToDB( LPSTR pUserId , // 用户名: l1 k5 w! I+ t$ v5 M/ o# i
LPSTR pConnString, // 连接字串 ]+ p6 n |2 t0 k( Z. U7 q. B
LPSTR pUserPassword , // 用户密码/ P4 Y4 F6 J0 R$ K" L3 I
ConnectOptionEnum ConnectOption ) // 连接参数
6 d. S' o* q" x( K( \{
' o! p/ z5 a+ U# e- J
5 K* W' K4 Z/ h HRESULT hr = S_OK; // 默认返回值$ Q3 y, t3 s7 G; T
_ConnectionPtr ptrConn; // 定义Connection对象9 X- I: g' `( X$ w
% I& I/ f8 F b5 v2 }4 r try
% G% H8 p- }/ e0 f {4 @# P Q5 E' A' z
// 创建一个连接实体. T' z1 r- O: `& h6 Z. Y' V$ H9 v
hr = ptrConn.CreateInstance( __uuidof(Connection) );- T2 s# B) E; o* `9 ~
: [( g5 \1 k8 w, u7 X1 R, Z
// 设定连接等待的最大秒数,默认是15秒0 l) r- |# y& m) o$ f$ _0 U: g
ptrConn->ConnectionTimeout = 20& y: m: l2 \5 Z0 ]/ b) ]) b9 L A
, j: ?* G* R U // 打开连接1 }5 [3 G7 O* P- }
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
) @! C Y2 A. H6 @, k" k. {! c: E return hr;
' G0 ~& ?- U4 \: z2 x o8 B }
& q0 C5 m7 V6 _9 P5 F) o8 [8 f7 D& k catch( _com_error & pComError )# S9 w1 n8 w! B3 |
{
/ _' m; E; F3 D …… // 错误处理
6 E( C( c6 n0 F( X return E_UNEXPECTED;* @9 |9 Z) ?! U3 B# \
}
g# b2 O1 ?+ h( Y: z/ }}9 g* t% C) A* \) Y9 D, F
" k2 J% Q0 X, R( k0 k
# ^; ^4 n4 b6 E8 ^" @4.执行一个SQL 查询,得到数据集(recordset)
; ~# w* o/ K+ v G6 E* r5 d+ N( m5 M0 I. @$ ]) ^; [$ ^. T
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
' F \# z& L5 B" \) \# ~{0 [- `: \. l+ W1 ?( ]2 g1 ^
try
5 P) i. J: v# K2 o* S1 { {
( ^9 \' J& {: n* u/ H( W; A RecordsetPtr ptrRS; // recordset 对象. `+ V8 J% I. L) V
- h0 v$ W" q0 u1 ]0 f& J7 v
// 创建recordset 对象实体
# b. U {- X/ `$ \ ptrRS.CreateInstance( __uuidof(Recordset) );
1 K: {0 S* l- X5 @2 l ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, G+ L$ U6 F" J, C. `$ B6 [7 m" |
adLockUnspecified, adCmdText );! [9 H7 ~- N, X! b, y
/ x5 ?; w8 D; J( V9 f0 E) \ o! L) }! y 或者& V# ~! |6 r3 w) T/ s! R3 F
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );( A; N2 s- U( I! M0 X
return ptrRS;% D7 @; J2 ~/ `% ?+ L( D5 x
}- Q( E* d+ X! W0 ]: p
catch( _com_error & a_pComError )
. w6 }9 I; R, O$ E; m. c6 i {3 [9 X+ z7 ?9 t
….// 错误处理3 c* p( `! k7 Q: z
return NULL;
, C- P5 X) ?5 } ] }3 V0 n& j. Q! w; f
}
, t# Z; u' C' `
, d& F) Z, Y' ]0 \/ b
" N" |* a0 K! k" g. r$ L- ^5.通过数据集(recordset)得到列的名称
S4 H4 a5 o' }. u# x/ ^) J& N1 c6 s; L7 y6 b# d$ |2 p
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象$ t# Y; v5 p5 E1 c% d+ \
char strColNames[][255]," S* M3 d3 }. G
DataTypeEnum iColTypes[] )
& a& F* z" L* ], @+ W: y- o{
5 `4 x4 {: S/ E try
v: s. b- C& @5 ~1 c. u { // 参数变量
! G$ G' d' ?# c1 i7 F6 x" | _variant_t l_vaIndex;$ A2 V* R N7 a0 G9 M! _& ?
" f; t) [/ E- y9 g$ }
l_vaIndex.vt = VT_I2;
% g* b5 Z3 O9 F$ @% l' h/ f0 @1 ] R9 u) `
// COLUMNS总数! U/ e3 P1 h5 z, S
long lColCount;
- [. U d5 ^9 k5 @: a# Z s+ B: }% C$ [ C8 j3 E
lColCount = ptrRs ->Fields->Count;
R) ^' H7 t& }: k& d
* _! y6 o4 h9 }$ d7 j // 循环取得列的属性和名称7 Y1 O; w8 A- Y3 J! M% J: B: E% E
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
0 c- u, E4 T, h5 z! ^ {; G$ P- {& g7 H b; P2 B+ u
l_vaIndex.iVal = iIndex; // 设置循环索引# t- D; z# w. Q2 a
8 T6 g6 v0 C2 V4 v( y) [$ m: X* O // 取得字段名称
1 S/ H1 j4 }: G1 U, Q. _# N/ z sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);, M4 C$ C. i! a% Z o* W
" t& \3 @' O& n& Z* l: j9 b1 } // 取得字段属性0 W4 \( v: f. A( [' ]
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
4 Y9 Y& p) x L0 B) ~: S% R }
' q1 M) I# V+ Y) L/ w0 s3 a9 @ return S_OK;
) D( @9 e# _+ y& e }
% Q' }& P Z) g) g) ]% B4 s+ k: |6 e catch( _com_error & a_pComError )
) H# @4 o4 }; I7 a, a2 Q {7 Z& Y; W1 m. X* Q* l2 }) |/ n) l
…. // 错误处理9 `) R4 u1 j( a
return E_UNEXPECTED;! j9 E$ n6 n( }; `
}
& Y) t U3 u7 E! N E4 c catch(...)
. Y- f" B& i# y) n {- g7 x. J) X/ b5 f$ R1 }0 g( f9 R7 m
…. // 错误处理3 x8 a p+ C: b" W& T
return E_UNEXPECTED;. B. [0 J8 y# n1 S! {
}/ r, b9 A% ?( b! o% a& Z
}: h% \) \: q, X/ |0 V4 e2 H, f5 g* D
( x' y2 p$ t; J
# Z1 o+ _/ X0 p: E6.通过数据集(recordset)得到当前行记录1 f8 C% j+ G- G4 }# w
. A; w% `: e9 LHRESULT getOneRecord( _RecordsetPtr ptrRs,
; a# W* R7 g5 m' |& U+ k const long lNoOfColumns,: J% _- m+ M7 T, ^: C' b& _& p
_variant_t varValue[] ) d2 h* z( Y8 e r
{8 g; ]/ N& Z8 a5 s! \
try
9 L& F" @. P7 C* ~0 b' y {1 V2 b/ U% V3 F2 q( S1 q
// 参数变量. F4 H4 G' {6 A# N* }2 |- \ U
_variant_t l_vaIndex;( l: q8 N! J4 b3 H, P0 z+ C6 Y
l_vaIndex.vt = VT_I2;& B2 U% H0 S8 E; @# [4 q, B
6 B" x# G7 c& O! V! d // 循环取得列的值6 ^' ` f) h& ?: }3 t. n* f& J
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )5 t: ?- l6 Q8 p$ q/ ~6 A2 B
{ ) [! \3 |8 }% y" s4 S: P1 n8 N" t
l_vaIndex.iVal = lIndex;
- B0 ^8 j( _: c- m- h) {6 {
, ~) @3 K, T" ?3 A // 取得字段值" a. k4 x; v4 v2 a# P! x. B) K
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;% b& A! Z) k. i+ C0 a- [+ ^& t: q s
}
) g5 [- J. ]- }) z$ D7 Q6 L2 b return S_OK;
+ j# w2 {+ l( ^) b0 s& C/ r, c8 p }) b( T8 o) J2 k
catch( _com_error & a_pComError )5 v( h; Q9 ?) `$ C% [/ E. w
{
* C4 i+ s# {# W- p, i- z …. // 错误处理
; c1 g! B: e- y2 d return E_UNEXPECTED;9 J1 ]) o8 V& D' l- E, a7 e1 S8 Q! c
}
4 B$ v" r; E* _ s# _5 } catch(...). t* @. D) ~- F; z0 T; X( R
{
) y; g- @" [* v; @% I4 P' A9 _ …. // 错误处理
# L: ^9 F$ R0 c. _" ^9 g; \ return E_UNEXPECTED;7 g$ Q5 U: a' s: W& ?
}0 r) j) M2 a6 _4 P R
}# ^4 m3 f+ U% V' b
3 C/ H/ Q! Y+ K& }) ~1 M
7 R/ K, O6 v0 Q5 I& B
7.出错情况下错误信息的取得
( P; l4 U3 n! S6 I9 j: z6 P2 M6 X2 q& U5 f* N
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );- H6 B( f5 r0 ]/ H' w
{
" S* J6 T: [2 B- P) g9 ?4 U // COM 错误取得 u8 m, ~- ^ C9 A* P+ [
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
$ B3 R$ F" D( @* x3 I char lpComErrorStr512];5 e! R2 E( Q% v- p+ a4 i/ c) }
& Q: u7 ]% O) T/ u. e3 T) | sprintf( lpComErrorStr512,( |" ^# N6 }3 I- { @1 W
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",/ X8 d4 F0 E& R. y
pComError.Error(), // 错误编号
: x- v1 T6 `4 z4 x! a4 R pComError.ErrorMessage(), // 错误信息9 {4 Z! h) e; A8 W% x
(LPCSTR) pComError.Source(), // 错误源
/ ^) |. I4 E0 x* v (LPCSTR) pComError.Description() ); // 错误描述, W7 R1 s5 b3 G5 d8 D$ V
" d, \3 U% Q' z+ J+ ~+ T: e8 d // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息) b' A& V, {5 K, I
// ADO错误取得
0 H- I! h7 E$ Z% ]
8 J0 Y9 ^' W P3 u' ^' p0 k ErrorPtr pErr = NULL;
( k( C. N/ b# J9 r7 } if( (ptrConn ->Errors->Count) > 0)" o9 F2 X+ T k9 N. ~
{! C& ^! F( O2 t
long nCount = ptrConn ->Errors->Count;
9 O- o6 E) C9 N1 ]; T for( long i = 0; i < nCount; i++ ): m- D% T! Q# p: |, E- J1 r
{
) ]+ L/ m% Q+ D9 h pErr = a_pConnPtr->Errors->GetItem(i);$ ^) j# c& Q4 R. u
# T* N G! v5 F
char l_pchErrorString[512];& R7 p" l b" ~, m' `6 P/ X0 ?
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",( ]7 D4 E5 P# f6 s
pErr->Number, // 错误编号
7 ~3 o% t0 e. p& H pErr->Description ); // 错误描述
/ J1 ~# S; o7 n R" Y; f2 | }) T' p. @. t+ @( h( h! f& u
}
+ h d6 ]2 ~6 g% V0 D# F% l6 ^0 v! r1 c# y
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问" n" e& \% L7 R* u/ V
// connection 对象取得错误编号和错误信息。 |
|