|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
6 @8 H9 O# F0 Q, |9 ~( X% o" V5 @# ~+ r+ Y- f5 U1 r0 F9 w; i# g
1、 用import导入ADO 的 COM 文件msado15.dll i6 p3 w% X0 H: `9 w
: j3 N9 o8 i9 t- F% v* Q
例如:5 ]2 N, r) M8 h+ Y6 U0 U* A" Y/ X
( ~) Y- [7 j. f4 o
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\* e) w6 s. c9 {
: s! I' X7 \( L. } no_namespace
* ^ y ]% a4 P/ K9 Y4 ^
5 D6 y. H( i K" b, [# H: u4 H! R7 L/ E$ I1 d
2、COM 使用时初始化4 a) W5 o0 S1 r% E! R# C
- v' f9 Z3 A* E: J8 d# QHRESULT ComInit()! H% Q6 N' _" O) J% V, x2 [. j
{ 2 |# Q3 |% I! \) L1 u; N$ ?
HRESULT hr = S_OK; // 默认返回值
: b2 _0 v2 R* R7 C1 U7 b3 F+ k if FAILED(CoInitialize(NULL)) // COM 初始化调用/ A6 ~/ ^8 C' ^- d4 X! N
{
4 A$ T4 P* J+ R5 F9 C5 Y CoUninitialize();2 g: f8 z9 c0 b2 c
hr = E_UNEXPECTED;* u6 M3 u3 N' Z% s) p$ \
}
' s1 b9 y! H7 I! d return hr;' q0 i5 R9 M6 v' O: p4 n+ h" V( ~
}; F$ h8 l* t9 h9 }$ X0 M2 X" v5 E
( L" G+ F8 G) a. T. F: s/ G- s
/ O( g1 X0 U2 R6 S5 h8 x
3、建立数据库连接+ Y: v& \. G$ D& T, c) n" E$ x
, o# v. ?$ g% I: S9 @HRESULT ConnectToDB( LPSTR pUserId , // 用户名8 A" Y' Z9 E$ w9 K
LPSTR pConnString, // 连接字串
* N7 I* j$ Q7 f# U1 A$ f5 s2 q& ^' A LPSTR pUserPassword , // 用户密码
5 m/ K; c Z( E6 k9 ~! h, D+ T8 y ConnectOptionEnum ConnectOption ) // 连接参数$ R; `4 i6 B/ d' G( G3 f* A, ]- e
{
: h" b. Y2 Z) R' Z9 u, E4 }$ c
0 h4 n3 z8 i3 ^$ `: x& l* M0 T( l; e HRESULT hr = S_OK; // 默认返回值7 P" r0 H9 O: N0 l! P, B9 g! `$ ?* g/ F
_ConnectionPtr ptrConn; // 定义Connection对象
$ d9 d" ^2 j5 w' S5 H
" r) K- T4 p6 C" { ]2 J: [ try
, Y8 f [2 G$ F4 o! P4 Q9 w& n {
) t' ^! k% c- o2 O' A1 Y7 Y' Q: ^ // 创建一个连接实体
( X3 T7 e( B- H+ c; n hr = ptrConn.CreateInstance( __uuidof(Connection) );7 P3 ?7 b' v- t! V
0 G% U1 g T; e% Z8 D# x // 设定连接等待的最大秒数,默认是15秒 x, }- R7 j5 H7 v7 a4 Q' E
ptrConn->ConnectionTimeout = 20
& T2 b8 o* U* B3 b9 F$ k
1 F4 s+ u. y" S, h2 a4 I // 打开连接
4 I: t+ \+ Y% ?% Y; x) l# }; ^" f6 @+ t hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );6 S# N+ d+ h3 E
return hr;
& v$ I9 h! W7 q1 g }: h. E) [+ O. r; P* Z
catch( _com_error & pComError )
# Q' \( a# {+ ?* Z6 C, \; c {; o$ T8 I# N1 B( I
…… // 错误处理! Q( E$ H$ e2 B2 V
return E_UNEXPECTED;8 v: C0 A7 K: B d7 G4 l( }
}! ^$ X! o2 f* |: b/ [: U% K- U
}
: } Y5 U4 f! y0 [0 t* o; ^" ]* g' Z0 Q6 y h4 [2 V
8 A4 `# v( l1 B* I
4.执行一个SQL 查询,得到数据集(recordset) K2 y& Q* Z1 B3 h/ d8 z+ c
1 w6 t- i8 G+ ^; ?) F_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
. Z& G! H9 n. n- Y6 `{$ K2 Q4 v* D7 q; M
try
! e0 [. k9 D9 n8 d6 z# a/ s. A4 `. G {, R8 Z8 b [, ^
RecordsetPtr ptrRS; // recordset 对象
* O" ?6 p; b0 p" F' M1 u4 \. S4 R' E1 C. J
// 创建recordset 对象实体
6 }3 c6 q* E: a+ J: i) W& P ptrRS.CreateInstance( __uuidof(Recordset) );
6 W2 K/ O9 ]$ E3 m- j: z W+ W* H, q# _ ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
! {. {3 R, w7 T& s# s* r% radLockUnspecified, adCmdText );
8 s1 b+ N$ {9 H/ r+ H4 p6 [" ^0 t" P
或者) M2 i8 G. ~- f6 g
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
, d9 O" {1 j# i2 I4 J return ptrRS;3 A) C' j( B; I- J8 [. Q
}- X6 [1 e0 H2 x( V: ^
catch( _com_error & a_pComError )1 \, Z" R% V* t
{
5 q6 |7 q- h: c ….// 错误处理% B% k; B+ M& E, n V
return NULL;! \, b( X/ m9 V; h, Z) X" X# a
}: Q" E J8 R+ j8 T x
}. N3 y; g% r' C) K
0 h& g# e. g: j
$ s& d$ M/ u* w: k2 |! N! e% C
5.通过数据集(recordset)得到列的名称
# j- ?* D) Y1 Z1 l4 m7 ^$ Q6 u7 a4 n# j
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象1 l; m& E) L. x) @- ?( O
char strColNames[][255],1 ~# ~% ?8 M) f0 ?
DataTypeEnum iColTypes[] )* u j* H+ i! G' K5 I8 B
{, L- z& e U, x" d' `( e
try
, \" }' k. M. O- R3 ? { // 参数变量" Y- A$ J8 @8 j
_variant_t l_vaIndex;
: n+ e( O$ h3 b- J1 q( B' z! h. m# u8 z. p& E
l_vaIndex.vt = VT_I2;
% m3 C5 v1 x5 a
- k$ N, l6 \. p/ T // COLUMNS总数- N. _7 W; T; n
long lColCount;( s2 y" A9 [1 ?. G& h, j) \, S
% M. v: g z7 Z+ `1 j
lColCount = ptrRs ->Fields->Count;9 g1 i- g. j+ L
7 W2 z* ? T; K3 M% T6 l7 [
// 循环取得列的属性和名称
( i4 d1 v }; B( i/ h) t for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
$ Z6 Q5 X5 n$ `8 u {: v8 [! c5 i+ A
l_vaIndex.iVal = iIndex; // 设置循环索引
4 O* l& B1 [2 x8 f' p3 |+ l) w3 I$ b- D* v h
// 取得字段名称: Q' `1 x# b+ k$ m N
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
) R$ e! J# p/ Z# I; S
3 x1 R# Y& z/ ?& b0 c% S // 取得字段属性
# x8 L' ?4 X \. d) w% u3 ` iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;* e7 A& q# {; C, Y
}$ c. ~5 ~8 V4 x1 W' d$ i$ Z1 Q2 w
return S_OK;6 q: \7 u; \5 C; g t
}
; E% A7 I9 \8 N; v; u% e catch( _com_error & a_pComError ), R0 }0 ^1 {' H" H. t' |4 V |4 L
{) N; h* D( J- s) }7 T/ e2 e$ k. J
…. // 错误处理5 H& A" l4 E" ^ \
return E_UNEXPECTED;/ w* f0 q" `$ |% r% a; J8 m
}/ z6 @$ Q f$ w4 {
catch(...)/ P( n' y) D4 W; X/ Z1 v/ \
{; S/ [9 w F4 `" f6 C- l
…. // 错误处理0 p$ m D# t% A; Y* B4 Y L5 M8 Y
return E_UNEXPECTED;
( M* F, V" i2 f7 R( `5 L. B. k, r9 R }: l! t1 O3 F8 Q+ D7 E" H' G8 A: ^
}* ~; e$ y/ D: [; M7 p6 `( b
- K4 s+ M; B: A: d: j l. N1 ^( m
3 [. Y' E: U, d" Q4 e6.通过数据集(recordset)得到当前行记录
, z$ F& |8 b6 u! X
" s8 U" `/ V' n# vHRESULT getOneRecord( _RecordsetPtr ptrRs,+ i& T+ ?# d" E( a
const long lNoOfColumns,
6 r7 h0 [/ `! ^* D( [: h* X _variant_t varValue[] )
9 K$ N1 \/ ?! g. x( H{
& S3 h4 V C" m3 {, D3 s+ w. q try; T; h) Q. F6 p2 |
{, s+ b6 X/ c' N
// 参数变量
8 A/ B) {; X" m; T _variant_t l_vaIndex;
6 I/ X5 f0 p, D! a1 D! F! r& m/ v l_vaIndex.vt = VT_I2;
7 [( s" Q9 Q# ]$ T& G4 W5 ]* D$ ^+ ]" V8 @
// 循环取得列的值) J9 K# |' e. Q2 z
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )# p2 g% M, d8 U1 B# S6 J
{ * I) |2 h- U; l% j4 j9 \
l_vaIndex.iVal = lIndex;* K5 i) D( t2 u3 p. K
2 t* J6 J: g7 d A7 u9 } // 取得字段值
) ]9 A. c- c3 L2 f, s$ @+ i varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;2 A1 P; e( y/ I' j+ b
}6 {2 y' f8 [1 E& L+ n ?
return S_OK;! G+ F) J& S5 w! A
}
% \/ u* d O3 O. U3 i: b6 t catch( _com_error & a_pComError )
" ?0 Q8 E% y1 x {
/ f0 I* x* n2 E7 n7 W( ~0 f- c …. // 错误处理
6 t7 ]; z) Z' p+ E' D9 s return E_UNEXPECTED;) W$ a. x+ s0 a, W' k# d
}: d+ I6 n8 B2 `3 m& s2 S8 x
catch(...)
# x/ ]1 x X- w2 m' d {, X" ~1 r9 l4 c2 G
…. // 错误处理7 G d' v. N! J6 b% L
return E_UNEXPECTED;
1 F7 T& R1 f; s, Y }
$ {8 O6 ^7 t% o y2 R$ f, [}8 n0 h- m2 O1 f1 O2 m
$ s/ Z+ ^! K, \) O8 ?! }4 }: n; O2 r% `3 C- [2 B- q& I5 X
7.出错情况下错误信息的取得1 m* C6 @( q9 R
, h/ v/ G% f* Q! ]& Z4 }void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
( J" s3 S' o- H5 L{# y/ a/ `# }1 C' R5 g
// COM 错误取得3 }3 ~* j( B: J) M& s. ?
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
6 _5 u6 O& Z; A' T: @5 @ char lpComErrorStr512];1 {+ j* B p! i# O. Y Z
$ t6 l0 d& ?3 }5 I sprintf( lpComErrorStr512,% S3 L; s- M; x6 A; y
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",, m; s$ F \' D4 _- ]/ Y4 q ?, g
pComError.Error(), // 错误编号
1 ^* K! ]5 P% A) S7 x4 c! c5 u" ^ pComError.ErrorMessage(), // 错误信息
{9 e! x" n$ D) d" S ]$ R (LPCSTR) pComError.Source(), // 错误源3 n+ K* V8 a% R' S2 M' L
(LPCSTR) pComError.Description() ); // 错误描述( u( k5 N6 n$ B9 P
( k4 T" d$ u: D: u" |* B+ m
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
5 y5 R& b3 E7 U/ L8 s // ADO错误取得) b2 Y) o% D& p/ u
7 E% z- w, P, i
ErrorPtr pErr = NULL;
6 D" {! {& z5 O# \ M if( (ptrConn ->Errors->Count) > 0)" X1 r& |& ^$ ] K$ E: X8 h
{
7 C, h; u7 u) @* @1 w" T4 k long nCount = ptrConn ->Errors->Count;
: I6 W7 I& g. G/ }, n N. C0 { for( long i = 0; i < nCount; i++ )- G0 c% T' j* E: d0 Q1 p
{& e! z& h% g1 a5 b( h, k2 k2 P
pErr = a_pConnPtr->Errors->GetItem(i);) ]) ]: f' s1 }% z! l4 I3 ~- B
( v9 T! |' E" i" V char l_pchErrorString[512];
) K3 s, U, ~3 | B+ d sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
9 M( {- C/ P9 N$ _5 z' h, X( V pErr->Number, // 错误编号
4 |8 E( ?0 _& X" p pErr->Description ); // 错误描述0 ^0 }0 Z4 U" ~$ B* X! [
}: M! @: r! e7 `3 s- s4 N2 ~- U
}
2 O/ Y' X, l: Z6 N9 g! o# k: V% h7 ?+ z* q) `
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
+ ]$ N, H6 V* l2 k$ n t // connection 对象取得错误编号和错误信息。 |
|