|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。& l8 X% z- A. H
& t( W2 e7 u( \0 [- r3 ^4 z1、 用import导入ADO 的 COM 文件msado15.dll2 G5 r) j9 z9 y2 `, w& P+ g
; i- P; _' _9 q |- p# g1 K7 l) v
例如:% t( o7 F+ F6 L" r* ]1 Q
2 v3 t5 b* c, e/ M: f2 U #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
7 ?# T( d8 ~! f {# V. x& o( R' _
7 N4 u/ Z9 [5 Z' i" i* S no_namespace r) y8 y- w/ G9 t( {, y& B8 g" J
6 K' u, l: ?/ D1 S4 e, W
3 s" }6 ?# e: d; P
2、COM 使用时初始化
& D5 D4 K5 C: E( C4 V: q8 T' \5 E+ G3 b3 U, M B Z+ `1 j
HRESULT ComInit()2 L! \( M9 _6 o8 a
{ + [, J$ U. [: k( s; t3 o
HRESULT hr = S_OK; // 默认返回值1 i- I$ ^% \3 i& z" p, E3 r
if FAILED(CoInitialize(NULL)) // COM 初始化调用3 o. A) ?) e) b" e- l9 |
{
4 f! w' s+ _- U# W6 R, N3 y CoUninitialize();" {: Y4 x! M+ }' s& T7 m
hr = E_UNEXPECTED;
+ b1 o! e. e- {/ P6 H0 D4 O }
9 j& x" Q6 M# u, N* M4 z9 Z! Z: w7 f9 Z return hr;1 T+ F( A2 O0 c% |
}2 n( h% a5 Y: n8 }0 X! A- G
* H! T m( f! h% @
W8 Y" M, k7 ?& g0 l: B3、建立数据库连接' N: _+ W- T3 @" B
' {% ]6 M9 x4 a1 l* |6 h6 d5 AHRESULT ConnectToDB( LPSTR pUserId , // 用户名
& V/ T5 a& w% C; } LPSTR pConnString, // 连接字串
$ I; P8 u; k+ r$ S4 i LPSTR pUserPassword , // 用户密码
1 v7 Y$ ~2 Z! E- }" Z! p7 S6 z q ConnectOptionEnum ConnectOption ) // 连接参数
* X7 ~- Q; G; I( r3 l& G{) _" E0 s: _5 O1 t1 d+ }& S
; {! f' p9 j0 |
HRESULT hr = S_OK; // 默认返回值
! A$ x3 r# E) u: G6 K8 K _ConnectionPtr ptrConn; // 定义Connection对象! f) E7 E& M! E- T
: ^7 W# _; U* A* v+ o try! Q3 h- s9 e/ V3 O' M) V k9 G; e
{
' k1 ]& N: X2 V' X9 h. I1 P // 创建一个连接实体# O, @1 U( r7 n/ P5 s
hr = ptrConn.CreateInstance( __uuidof(Connection) );
3 N+ ~; v8 Y0 j: d% b; C) E0 u) x9 N( }( r a1 L0 v
// 设定连接等待的最大秒数,默认是15秒
2 A {7 Y% i: j ptrConn->ConnectionTimeout = 20! c# v6 m) Z1 Y2 z8 x! ^. q ~
! u6 U( E3 b( E2 u1 p+ f) z
// 打开连接
6 E6 P9 J/ @4 }" I& ?; _ hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );' P- p) P* l, N& X: I3 D
return hr;2 @& n6 Y1 v% Y( c. m' J
}
% `" D& l) \6 a0 _# v6 t4 I catch( _com_error & pComError )% w) Y' W$ c% T7 }& k/ S# S
{
/ E/ ~5 o; H. U. }' Y# F: [ …… // 错误处理 ^* }) _ z) s3 n- G, ~
return E_UNEXPECTED;
' E3 ^9 h& b) S" ?' ^ }
" P) h8 o# `% Y} Z3 Y" G% {: o8 h1 o. \7 i+ I% A! c. Q
8 @6 s" }4 f" e- W4 J7 a% l
9 A3 t! ^+ l3 j5 _
4.执行一个SQL 查询,得到数据集(recordset)( i. Y2 T7 {3 z3 M% G# C
% }3 y) o+ D2 G3 R_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
: ?$ A8 x. m2 {9 M5 A; H6 z{
6 Q2 c) r7 w" `2 l5 s, r% ?9 u try: m9 s. Y' j. J# t
{
* r6 S* Y: W4 z+ h0 E2 a3 J RecordsetPtr ptrRS; // recordset 对象
3 f. q4 n% R2 W! x% q) z% N6 a) A7 q8 b/ m0 P c
// 创建recordset 对象实体/ {# }& H& } B0 @2 r+ X
ptrRS.CreateInstance( __uuidof(Recordset) );% p, r# x! @& C1 ^
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, 3 r+ F* `% f9 H6 @% b8 _
adLockUnspecified, adCmdText );
' R" Z/ {% E) Y# T6 o% t
1 C3 c7 G7 c5 B. W3 H 或者% W/ M! i# F- z
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );' Q! C4 L' W% i' R7 m0 ?. W; ~
return ptrRS;
" @* {' u# d H4 L9 Z+ o! z: x3 h }9 k4 j, k8 u2 ^1 J5 Z
catch( _com_error & a_pComError )4 E1 A: w& `% Q! q% w* r, q
{+ ]1 A5 Y+ N& \% a& `- C0 e/ F6 J
….// 错误处理
& K- O$ h6 e- P' Q( w A i+ i: f return NULL;
! ^- A& p7 e9 V8 ` }
; N0 l N& L* x! u}2 i G( |" A/ p7 ]# s. F/ Q$ @
. c' i5 B. \# L- M- Y. `$ E c' ]+ p9 N
5.通过数据集(recordset)得到列的名称5 O+ g! D. Q; x1 w1 G
/ ^4 g4 L+ ~$ t" s$ f* F5 P0 V
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象. c4 J8 d1 A6 \" g
char strColNames[][255],- a3 Z; T# \( q7 w% ~
DataTypeEnum iColTypes[] )9 f" v6 S3 D5 O( I: i" v# F9 I+ ~
{( {# ?, c* Y$ c) I8 X# u
try
( X8 y. }: S% w* l8 ~) @ { // 参数变量# T/ b* P7 k# p. r3 A4 \) [/ w
_variant_t l_vaIndex;# n4 `8 d6 {/ t# F
) M& Q; Y# K1 `' g: e l_vaIndex.vt = VT_I2;
4 Y0 I# z/ Q+ n4 i, b' R+ c( [9 {8 v: g
// COLUMNS总数4 L% v2 ^. F" s; o2 y3 I) A
long lColCount;( q f& |) A8 w+ I: j0 l
0 |- z$ |% n1 t: m/ G1 H3 |# e lColCount = ptrRs ->Fields->Count;
; }3 ] M9 ?2 S9 ^, G. G- [; j/ t# x# D& q# x8 f
// 循环取得列的属性和名称, O; m& R* z6 m' X
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
0 r* v8 [7 Y% n2 F {8 _( a$ T+ {; @
l_vaIndex.iVal = iIndex; // 设置循环索引6 m/ [% o6 Q @3 x) s: z6 |9 o! |
7 F' f! {. N" i" N, x // 取得字段名称
* H& M: Y. u+ W0 p3 ]" X sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
" M0 k: k2 U5 @) ]1 K, L! T3 z. W) J* Q7 A! K* K+ R5 ^
// 取得字段属性
1 E+ r( W' ^- j* k7 \8 M iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
6 P9 ]/ C- H6 i( F$ z5 i }
j1 Q5 T; o& | return S_OK;
, K: m0 d' \! V7 x$ V }
7 D, W' N7 {+ J2 L catch( _com_error & a_pComError )1 K+ A% M# ^. g* ]
{
, U8 T) ?3 ?8 C …. // 错误处理( {2 e" d9 N5 s o. [: q
return E_UNEXPECTED;
9 `# s8 q f7 d }0 C) \: `) K1 R& q5 G
catch(...)9 B9 w+ r7 ?, b
{( ?8 |8 p5 I: M. d( O
…. // 错误处理
, n6 K7 N" D% s2 J9 R1 k% u return E_UNEXPECTED;
8 d( N; f8 D8 q; @1 D1 W }% u& ]: m6 l4 N0 V& J
}/ l; a2 q& t3 x3 B: W8 L% d3 {
! W- `' q& Y! B
' g5 w4 W" D# |9 n3 v0 `6.通过数据集(recordset)得到当前行记录$ e& j- h: O4 Z0 s0 ]( D" v
2 L% r/ T u# @3 qHRESULT getOneRecord( _RecordsetPtr ptrRs,
- u! ~" H0 ]( n {7 Y const long lNoOfColumns,
/ Z* ~' b; G0 @* V1 S J _variant_t varValue[] )
$ R4 G1 U: m7 l* x$ K{) N; K3 b4 Q; f" c
try
" G$ I8 x4 Z$ F4 G! i6 j$ m2 E) r {. j1 h9 Z P' O6 ^4 l: u
// 参数变量% _: Q' r; K9 v1 ]
_variant_t l_vaIndex;
I$ h3 N) p- [& k8 @2 B l_vaIndex.vt = VT_I2;! K; s' {0 E% g# s z! h
7 x. @2 M3 Z0 U$ n: g$ j; Y5 c
// 循环取得列的值" f* I! G7 g' J! O6 B& J* |
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
2 I6 U: V' E5 Y7 T1 j {
: W4 a4 o. ]1 r l_vaIndex.iVal = lIndex;& Q0 h% e+ \/ i. L ~ |: w& L1 c: p) ~& t
' x. v& k, m, x! S4 x // 取得字段值
$ Z( W' h' Y, b6 i* d& j varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;; [3 x; x) {4 H d
}6 E% ~% p3 B% K) c7 P
return S_OK;- N6 a3 c' E, b( N' n6 z5 s
}
0 D: F A$ f l2 ]7 |+ A$ w catch( _com_error & a_pComError )
5 W. n! E; `( ?3 l4 a {
2 _6 `) y. X4 o) `. l3 |- x …. // 错误处理
9 A' s$ h+ X! g& @2 E return E_UNEXPECTED;
2 W: t9 {: ^' U3 N( y' n( C }
$ Y' w- k2 l+ D6 X9 F catch(...)
/ H6 D& G7 W5 u+ f; ~# d; N {
& `* e# q; k# `4 A; l* V …. // 错误处理5 V. E4 i) h; S j# J$ G6 T
return E_UNEXPECTED;
5 ?9 ]1 c4 X: X }7 K# F6 c0 a R7 r. X ^+ u, p
}5 ?$ h5 o3 ~8 b |& a/ j& D0 d
& }( f( `2 @. t7 N' m; Q
( V9 A; p! [: w5 o x
7.出错情况下错误信息的取得
; g9 D$ `3 X5 o7 R4 P: d
) w' _& q& I( E" p1 ~8 xvoid ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
5 a. S+ m/ @6 [5 E- l{% o1 x* l5 J1 Q
// COM 错误取得& U; w7 \' S9 q: m
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
* C0 |$ a0 g0 u! c+ o: ^ char lpComErrorStr512];2 h. X5 p# }5 ^& k8 Z: w2 u: T% c
+ z5 A1 w; P; U" u; s
sprintf( lpComErrorStr512,
& a3 I- @1 v4 D _3 r/ J! {5 Q( q2 x "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",
0 X9 r4 _; j0 z; X+ D/ o; i$ C pComError.Error(), // 错误编号) W3 r# c& o9 E
pComError.ErrorMessage(), // 错误信息
( z8 t. D% n& r: e( w* X4 s/ v c (LPCSTR) pComError.Source(), // 错误源
$ |& N Y% @0 u+ J, o (LPCSTR) pComError.Description() ); // 错误描述
# s! D% V" [7 {7 c+ s0 l
7 M. \( f5 z1 j- t/ C% J! g; u // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息+ D! h4 G$ [/ d. }; v8 `7 \
// ADO错误取得
, g% [- q! F6 B) s3 X: f) t: q ?) J6 C" ~
ErrorPtr pErr = NULL;2 U" d# g' f* l2 ^7 v
if( (ptrConn ->Errors->Count) > 0)+ Z4 W4 B8 c0 z& I6 O+ x! G! i
{4 _( Y- E% N& Q+ q' J+ B0 s+ Q
long nCount = ptrConn ->Errors->Count;
8 _3 p+ G- r. b2 J. [( g for( long i = 0; i < nCount; i++ )1 }$ s. p0 M6 B$ z
{
9 A3 r: e# ~0 U. G8 c. V& [ pErr = a_pConnPtr->Errors->GetItem(i); w! a+ t C1 ?* L) u
/ [+ e2 ~0 e$ q$ K( j
char l_pchErrorString[512];
4 g* A4 o7 i# @8 D sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
% U3 P- i" J/ @8 a( h7 I9 n pErr->Number, // 错误编号
4 J. ]8 R$ J. m2 k* r/ q! ^2 W pErr->Description ); // 错误描述5 O4 `0 a2 |2 k& \
}
6 T- |$ \* V1 r% t }
; v4 n; a" K3 v8 U7 w7 i, u5 f- B6 t5 M2 D" }; u( }
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
# U; p4 S6 s/ |# J$ C // connection 对象取得错误编号和错误信息。 |
|