|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
( M& c- G1 H+ s1 u" Z$ b
K8 h k- J6 T, _1、 用import导入ADO 的 COM 文件msado15.dll
1 P' X2 X/ v0 k" M7 X3 h0 ~( q. R8 m* T+ _. ^7 V7 s
例如:. r7 E& n" D6 d$ l* K7 `6 d
, d* s( ?, |5 n5 S( W
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\: b$ K( O6 T/ Y& Q7 F* w# t
: a2 @4 U8 _$ n8 l
no_namespace
i) d$ `" k, @1 V( D' n/ _2 t7 A7 z* z+ P; g# Q0 L5 c1 z
0 K" Y/ t& c, l4 K- b" f2、COM 使用时初始化
6 S0 g* d3 D& D: c0 b7 k4 N( r) J" l7 ]& M Y# Q
HRESULT ComInit()
1 ?0 l% N: u% X$ Y, ~{ , s3 L: L% E i* v. D# [
HRESULT hr = S_OK; // 默认返回值- W' B4 n* G% d
if FAILED(CoInitialize(NULL)) // COM 初始化调用3 n9 {; z8 ~* c, T# Z6 t* U
{+ Z& d/ o. M" s1 |, l
CoUninitialize();4 F+ t# q" A8 D- z- s: } ?% Q
hr = E_UNEXPECTED;
Y$ W& K4 {4 Q# { }
! F ^. z& j- Z- Q2 r' i return hr;6 I, K2 r S2 U0 X, ^0 ?7 A
}& U' {1 B+ R& P
% c. B5 E4 W4 }' _1 p- U! {; ~( ]2 L( e
- E, F+ g" G, l; c( c9 `8 p
3、建立数据库连接& r/ R. ^* I5 L2 U2 z
- \9 P. Q+ b9 `1 _# D5 s. m, hHRESULT ConnectToDB( LPSTR pUserId , // 用户名
8 p. h6 |" r9 T. `* q LPSTR pConnString, // 连接字串 / b }3 w" \" G5 b
LPSTR pUserPassword , // 用户密码
2 W2 c5 L1 t( r9 B8 W ConnectOptionEnum ConnectOption ) // 连接参数
* v* Z, Q' _6 T6 Z, Z7 A. K# ^{
1 |2 C% k9 H: J; t/ N# ^5 h# B3 u7 q$ u- Z7 d$ B/ P0 E
HRESULT hr = S_OK; // 默认返回值0 ~+ s: m9 X" a, |% I+ x$ p
_ConnectionPtr ptrConn; // 定义Connection对象; O; [7 w+ U d9 S6 H9 @5 U' Y
4 F* z! z+ [8 S E1 z
try
/ S6 W2 c2 { ?, h! o4 n& n {
. s( g. E6 [0 j4 ?3 @ // 创建一个连接实体
8 |# w: o& K0 G hr = ptrConn.CreateInstance( __uuidof(Connection) );+ a* l7 W. G1 C2 {# f0 k4 J9 O/ c
! F( a b$ F& n, [" i2 E
// 设定连接等待的最大秒数,默认是15秒
8 w5 W2 @5 \2 I6 M5 v: F- S/ b ptrConn->ConnectionTimeout = 20
& l, l! R2 ?/ I' B* a6 ^7 D7 i, M8 n8 i4 A7 r$ [
// 打开连接3 R; ?' E+ `7 J9 {9 G
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );2 n7 x& m% r6 z0 T- J& h
return hr;! j' L& d0 X) _8 I1 x" Q
}% G* Y* ]+ p2 I! g( Z6 f
catch( _com_error & pComError )* H1 ^" q* `5 d0 m
{
1 C3 n* Q' T# Z% ~! n …… // 错误处理
. W3 N' @. O' M& _ return E_UNEXPECTED;
1 G( m: t* R# p/ |* z }
: B! j% b! v* |* ?}
e5 B$ z9 J8 K( N- n
4 j3 d9 u! S8 E; C
6 |5 y2 B% W# @1 p4.执行一个SQL 查询,得到数据集(recordset)
6 m- w- @( F. U/ n ?5 ]. T+ w- j7 d8 i6 y' e1 ]- o, D
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )5 g0 d9 h7 I M& M) Y/ ~; s$ b
{& d& ?: J+ E! d/ z1 _+ W
try+ Z5 O, ]2 p- s! ]) A1 y
{7 T* h$ K& ?) p3 F9 G$ ?
RecordsetPtr ptrRS; // recordset 对象
. u: ~$ p' ^# f5 j% W/ D, ? Y! P6 V2 N) E5 s( {7 T K$ K; X( [
// 创建recordset 对象实体
0 x. [& f; u8 j6 B ptrRS.CreateInstance( __uuidof(Recordset) );6 Y: W7 I/ S; w( `8 c* X
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, ( s; o! y. d) H" z
adLockUnspecified, adCmdText );
: }9 r0 H' Z* d v: q8 n+ c
# q- p W$ a9 z' P. R# F$ J 或者
0 C0 K( ?" A7 X8 U& R7 s1 x# P ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
9 f. B( a9 B% Q) f2 d return ptrRS;
' J6 l- i" x& B( y" Q }
; K" b, K' O+ [8 n+ i catch( _com_error & a_pComError )
' ]; J, ?8 [( l {9 l: M/ `1 N5 z
….// 错误处理
7 n$ v) e* p( Q9 V9 n. U return NULL;* L1 y. N d. I3 ^
}: f7 U" @% D3 a! Q( I' p3 j
}
2 g& e" N0 ]% {% h' H" h% h$ p9 L' ^/ J& w% [) x# }; n
0 a) j( @& b; @( {" {
5.通过数据集(recordset)得到列的名称& g, d, V( Q8 R# x
f9 E0 H1 X# g. i9 d
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象0 J* O" n, O6 V* _
char strColNames[][255],7 ^0 n$ `7 U. d
DataTypeEnum iColTypes[] )
j% L% }0 R4 ~$ j* F6 l{
, x+ ?, t0 H8 q; z" ^) M try9 j! I: {# |: J
{ // 参数变量
+ V6 r$ [' l! b# H( }6 Q7 y _variant_t l_vaIndex;' R7 b+ f8 R% X2 {/ W0 N! {
% m; Z& _+ ~9 \! M" }
l_vaIndex.vt = VT_I2;
) Z {% y" w% g' l5 n- l6 u$ J7 \ F3 v) r4 ] Y' w! g2 i' G
// COLUMNS总数( p& o$ Q2 Z8 N& l; B& n& h8 I7 O% A) F
long lColCount;7 ] C2 c% H6 C6 w3 i `
% a2 Y) k5 M) G) o3 m3 r. c7 P lColCount = ptrRs ->Fields->Count;9 A0 z" c: Z* @$ n! f' h% b& `
: c" O( u6 \% O' ~+ J9 {( R
// 循环取得列的属性和名称
' D, ^% A4 g: X" E+ N: {6 m for( int iIndex = 0 ; iIndex < lColCount; iIndex++ ) M8 J1 \+ \7 L% q `' v
{, g( O) P% Y$ \ L- O) ^8 o
l_vaIndex.iVal = iIndex; // 设置循环索引
" N7 C0 H7 e9 n) A4 h P% D: e% H5 T `8 Z, u
// 取得字段名称- m* H* o" D! Z6 _
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);: N: o" S t. _9 f
$ J \2 ]( `/ q% e" l, k // 取得字段属性6 t: A1 @$ w/ V' ]+ N
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
( v' I k) ]* e3 H6 [, m3 } }7 M! F, r3 t9 h3 E2 u" {! E
return S_OK;
, E3 T( M2 H' z8 [, ]& V }$ {7 I/ z! Z) {: N
catch( _com_error & a_pComError )+ m8 v/ _# a; k- }# s
{* i- F' i( W" k' Z
…. // 错误处理- H& c7 A5 P1 v7 R# @
return E_UNEXPECTED;4 r% A; {" q/ ]7 O n
}4 p& Y& v# `! L% W) ?, b/ o
catch(...) P; I0 O& D# A$ y
{
0 U/ M7 y5 k7 I …. // 错误处理
" L& {& V" V5 ?* R4 [ return E_UNEXPECTED;( z! J; j) x1 I
}# N* h) X) [( a$ V5 R; j4 O
}! P) f& e; f" S9 c$ d
: M0 V$ u% r, x9 h3 i
% P) P8 t. Q7 }5 K- \6.通过数据集(recordset)得到当前行记录: I' G6 W% I6 z( Q: j" {3 @5 j. ? O
7 B" o; X( w- w+ Y: t) e. G
HRESULT getOneRecord( _RecordsetPtr ptrRs,
$ i0 p4 m. G: g! O+ e: ] const long lNoOfColumns,* q4 j( t& a" I; a1 `6 h1 N! u0 N
_variant_t varValue[] ); u; g$ Y4 M4 {
{0 ^+ d& `% f4 X x8 m
try
; F7 w, n3 @* g, F* ^: x3 F- } {# V& K+ i4 V! {) P+ k- q
// 参数变量
3 Z9 }/ v x1 Y+ U2 P( @1 ` _variant_t l_vaIndex;. E( t, I# h# G% h9 J* }2 e
l_vaIndex.vt = VT_I2;
0 {7 L, x- |; ?* l/ g* @ E2 c/ S! @! s
// 循环取得列的值& R7 c5 |$ _# O. ]/ d
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
) T; J! B" } u2 n { ' x0 G: H& t9 \) g- G5 D
l_vaIndex.iVal = lIndex;
4 K( N2 A4 E0 B" e/ @
9 a( ^" v& R4 @3 e1 ` // 取得字段值
; ]7 K, m! [. J/ ]' @: ` varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;! ]" w, ]& e( p4 F6 U9 |
}
' T% k, l5 g! x0 w9 W return S_OK;' a& Q/ s# e0 { x# B. h6 {1 T0 W
}$ ^$ ^# s9 P, d+ }
catch( _com_error & a_pComError )
4 X6 N# P4 t2 B- e* W+ M2 x ^ {# ^# Y+ ?* U' E0 v* j# ^( _+ i
…. // 错误处理
- {" A" Z/ l, z# C6 a+ ^% w return E_UNEXPECTED;; d* C6 ~. k7 H2 d: W I
}
3 ^4 e0 W l8 J catch(...)# z* v8 Z" | r o) }. _% J* f
{
8 `( ]" A# P$ V4 r …. // 错误处理3 `4 G' ^1 f% s# c
return E_UNEXPECTED;5 _) b- M+ O! V% d( m
}, p) W0 E- G9 ?: a+ s+ Q
}: Q* Z _2 y1 W6 e
# t$ j B3 H2 x* D3 h+ C9 s
) M. f& X h. a/ h
7.出错情况下错误信息的取得6 v% X) m6 V# G- M6 W
9 ~* o' }4 g/ i% s- S% c. qvoid ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
c1 u2 I2 [, ]7 P& c7 C{9 }: q5 o" y+ F( E1 F. e7 A
// COM 错误取得0 c; m6 D% U. O% t4 r& o3 F G% J. e
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
$ N2 U! H4 v7 Y& [( l7 ?, R char lpComErrorStr512];
6 X$ f$ E- m' `& i3 f$ V7 A: k z
sprintf( lpComErrorStr512,3 V2 p" \' c& y1 P4 w" \4 V5 g# i
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",/ I" K0 q x0 m* }9 t, C
pComError.Error(), // 错误编号
' E- X/ P- J6 {2 U+ N* g4 F9 W pComError.ErrorMessage(), // 错误信息- Z) X( o# p( I! _8 T% ?
(LPCSTR) pComError.Source(), // 错误源2 D( _7 o" s |8 l S7 O; n
(LPCSTR) pComError.Description() ); // 错误描述
9 ~7 R! A( K+ j8 O
D3 _+ A9 i* K. U9 R1 r7 J2 g // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息5 A$ H8 o. d! T+ i) y
// ADO错误取得6 ^$ x4 J- s1 _# f) [
" e A( J4 [: k# V5 X8 R
ErrorPtr pErr = NULL;
/ l+ ]# I: |3 f3 o if( (ptrConn ->Errors->Count) > 0)
- x9 _8 o: ^1 x' f( {0 i {* T6 c8 X% q" P/ t
long nCount = ptrConn ->Errors->Count;4 t8 \4 V" T4 z) k/ i+ x1 e
for( long i = 0; i < nCount; i++ )
6 N# W ]+ L. d6 d- W! b {$ y. n3 }: }9 P/ X( D# n* X) U
pErr = a_pConnPtr->Errors->GetItem(i);8 t, {. ^0 e- U" ?7 X" J9 w
6 H# y$ z- j4 D- k B/ k! ?* w3 ~
char l_pchErrorString[512];5 [+ `) u. L* |6 t+ V | U& x7 e3 q2 c
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",; M5 H$ M' m) ~6 F# D+ ` ]
pErr->Number, // 错误编号2 P% U h g8 l* l5 K2 M0 G
pErr->Description ); // 错误描述" M+ U* y1 g5 W+ @2 {
}2 u- ~% g, X( W# N2 a @
}
& z$ W. t& t l2 U; Q9 Y" D
5 n! G# a( m3 x. ~- K! v8 K // ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
$ p F1 N! S! n3 O* G& I, g // connection 对象取得错误编号和错误信息。 |
|