|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
9 [! Y6 Q7 M# L. \3 o8 U8 _$ g3 a" g2 _: H0 p4 p& V1 j
1、 用import导入ADO 的 COM 文件msado15.dll' ?% O& g1 b* ~# r0 L
& G6 m5 y/ R' F7 i# P例如:* Q2 P8 U& U; A$ B
1 f+ c, Q/ k+ Y0 N; C
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
. V1 A+ u/ v# C9 l+ e. y3 [7 \8 g8 L( U' |4 L4 J% L
no_namespace
& @, r! @; f$ E0 l; X( G1 L3 I/ r. t9 r p, {8 }" x% \
" U! `5 c# @" ^2、COM 使用时初始化
' `' e: o4 C- ]7 y+ Z3 c% ]
Z9 |% Z+ E4 N% A0 C7 }HRESULT ComInit()) I2 @$ D- k& L O' h+ a! H
{ 0 I' Z7 d& }5 T
HRESULT hr = S_OK; // 默认返回值
1 ?$ n' T, `! {6 D3 h( C if FAILED(CoInitialize(NULL)) // COM 初始化调用5 H. k% W! r% K
{
& W, p" c& q3 K8 [# P* F3 _6 _ CoUninitialize();
# ?8 Q0 z6 v: k7 J3 `9 z) j3 } hr = E_UNEXPECTED;
5 x T! B k2 _6 q! ?* d6 a# ]4 M }
, @/ c2 I% [/ ^- b) @; D% J return hr;# v6 t# w; m% N7 S/ k
}$ R9 b: A' q1 {/ X% h/ [ }3 P
1 h9 k1 L+ X- Q8 A8 k' Y2 s
Q% n& V4 l5 _
3、建立数据库连接- y- |) d6 j' x' p b8 W0 a
: t9 ^6 t5 ^/ I W5 L# w& [6 M+ v3 AHRESULT ConnectToDB( LPSTR pUserId , // 用户名
! a8 s; e4 v7 {' `% X LPSTR pConnString, // 连接字串
! G! X1 \2 A& O0 \! n* G LPSTR pUserPassword , // 用户密码
3 r N. ]& s; W: ]- L ConnectOptionEnum ConnectOption ) // 连接参数
& m" }; Z' |, ?{
6 G$ V G: E" ~, m7 ]* X! c
5 O. E9 Y& B8 k t' X4 { HRESULT hr = S_OK; // 默认返回值' \$ l. Z2 {1 X1 f3 X9 i6 g r
_ConnectionPtr ptrConn; // 定义Connection对象
! ?, Y `! {4 |: x5 |$ U i* F$ \; u V. P1 p; _9 i
try) J3 C2 e8 a' Z
{
) b/ S( O/ t4 D // 创建一个连接实体
! t# D0 M' Q+ I) T. }! ]$ _$ E hr = ptrConn.CreateInstance( __uuidof(Connection) );; F& @# \7 a. v' d) D
, U' |, R3 z4 }8 i
// 设定连接等待的最大秒数,默认是15秒8 D4 }7 J8 i3 z6 a" d# P
ptrConn->ConnectionTimeout = 20" t) ]! C' M/ b: @0 e4 v
! B" } i& e4 ?5 E0 G2 H4 u // 打开连接5 q# ^& ^3 d2 R( w" a; O
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
) e' @5 i2 u2 Q* f: ~- i W return hr;4 R, P& i! b+ v& Q+ Q0 ~& z6 }0 q' d
}9 n6 R3 ?+ C% P, }- C# y0 S
catch( _com_error & pComError )
6 t+ p; u% W8 s i' n1 e {
" w, p& T9 B; @- M …… // 错误处理
+ q, c9 c! L9 J T/ k2 I G return E_UNEXPECTED;& Q; W0 U, ^' p9 E# M, g
}) k2 R$ s; z9 U8 S; ~$ I+ }
}* H8 p ~- T6 ~
0 @: _: J8 K, P* O
4 T" N% d! X: p& R0 H4.执行一个SQL 查询,得到数据集(recordset)6 L% s, n4 u" t" Z$ |$ l1 k ?
, k, F k2 Y* w) |$ ]/ ^( M
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
. w# _+ J t& {4 _7 ^8 A2 L" F{- P/ }; T' g3 ^
try
1 q7 V: v( u3 r- R' M5 q$ N {
" E+ a* K4 n: V" ] RecordsetPtr ptrRS; // recordset 对象
: x7 N% y: W' y# D, Z, ?% S
$ j+ j# @1 Y1 ~( [; R( O4 e# { // 创建recordset 对象实体
& B# @- ?; S- K9 G- V8 y" U) Q: N ptrRS.CreateInstance( __uuidof(Recordset) );6 S2 o) q$ q0 d; z% ?
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
4 l* \3 r9 u% ]' ^: E4 t( r0 IadLockUnspecified, adCmdText );
) |9 I6 k! I9 w }
b" F' w! o" {( L2 i: K) n% q 或者0 ~$ H7 X8 o; h* z
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
$ F+ O) ~- G/ @/ l return ptrRS;' T# [9 l1 J+ K" n
}
4 Q) V( b, g4 t- `* T1 B: P0 m catch( _com_error & a_pComError )
( x' ^& k; y6 f3 I! I) A' B" O {
3 b2 q, Z4 k9 \" z3 D( @ ….// 错误处理
/ S8 F3 v8 J0 n7 P. |" F return NULL;
1 @" i, P4 C3 x4 ~6 l& _1 ` }$ V- M4 c2 y: x" r$ {9 s- S, [2 K
}
5 P. d: j( u. @: c/ }7 C& _+ B) v& y! I( N# E8 G
) N2 e$ J8 `% ?+ i& a" s/ W$ q5.通过数据集(recordset)得到列的名称
2 e l& G6 ^; `* W1 M1 H3 z2 l& l
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
$ y% Y( f' h6 ~5 W; @3 f char strColNames[][255],
7 g7 |' X+ s8 ?7 ]4 I) Y2 t DataTypeEnum iColTypes[] )7 I4 Z, E, b! } z* b
{ w" {. V& u8 i- }0 k" \, L
try
5 p; J7 H4 y& k, v- ^5 z* ` { // 参数变量
( j) D2 d6 c: z2 m6 ]- Q+ T/ a _variant_t l_vaIndex;4 E; e0 I( k. J. ~& f
! p: [* z4 c( K8 B0 A
l_vaIndex.vt = VT_I2;$ ?' O% [, h( N- J) q
0 D% p, `+ [" k; g" f* a0 H' P4 c! f
// COLUMNS总数
& n; ~' |9 z9 ]% Y7 Z( V- @ long lColCount;( L4 S& N# R. t: t! _5 J: O' n
0 K* B- ]& x0 P' S4 U, P
lColCount = ptrRs ->Fields->Count;1 \5 Q5 r+ h$ g" \$ }& P0 `. Q
9 H: n6 k) ^+ s( i
// 循环取得列的属性和名称
, e% u# N/ O2 S- e4 s& Y for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
6 _% t3 H* ]7 X3 b {
1 s( g' d& j) W7 g+ O0 H* C& W) | l_vaIndex.iVal = iIndex; // 设置循环索引( |& j6 }( }, D$ h, {
$ Z: S0 Y1 S) I4 { `
// 取得字段名称
: _& H2 K& v) [) z# N0 N sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
- ?# @ J# G+ [- F" ]$ \
) v3 |4 _9 S B, ?4 I8 b4 J5 d // 取得字段属性
. Q0 ? d. b9 Q+ w1 X, f: y5 A" ^ iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
$ O: Q5 Z1 l( h$ V( { }
" U# C5 d2 A5 K+ j return S_OK;1 L# I# y6 q6 E' g/ f
}# y$ l$ `: J' o
catch( _com_error & a_pComError )
: ]4 D" r4 |8 N% n( K9 `( Z1 W {# @& F- X& [5 _% C$ ?9 ?! K. L$ x
…. // 错误处理& p/ n/ l% Z& K
return E_UNEXPECTED;
( M; I% F* Z L/ g' J6 h+ t }8 ~4 _2 {+ P. P
catch(...)
' w3 J }; M& g L3 K" h {0 k# P6 ^: N+ Y- _* f# n! j7 O2 `
…. // 错误处理
6 E* x! ?) C4 `) B& a. G3 { return E_UNEXPECTED;
0 A) P5 g; o. a }
6 x; ~( {' t0 A3 T! R}
1 s% U" n" s* y* Z# _) Z7 `5 n( e/ y; }7 h# N$ G2 `
, f8 ^; f& K. {: U3 ^4 {
6.通过数据集(recordset)得到当前行记录. R4 C O: b3 Q( H" Z
1 H& O; a' ` u& t. n$ |* O6 O
HRESULT getOneRecord( _RecordsetPtr ptrRs,8 N) R& `7 K+ O6 I4 c6 i
const long lNoOfColumns,( M: c# M: B9 G- h* e: {
_variant_t varValue[] )) X8 ~; P& P; Y- V' t, |
{
$ V s$ r5 s u3 T1 A0 A try
* L3 w! _) ~- w7 s8 C {, u( l' f, E. t1 h3 y0 _' a: J
// 参数变量) R) u7 ^, z; E5 @: U; S t* C" z3 ?
_variant_t l_vaIndex;
6 U/ r. ~3 b8 J, I( C. ?8 @: ]* v l_vaIndex.vt = VT_I2;
- l; }& h" s) c' L2 X8 h$ Z2 A8 w5 Y2 P* e' A3 M
// 循环取得列的值
" Q& c% \+ F7 J* m v6 j% _0 M for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )+ i4 \4 P- c% s
{ 1 q! Y: o/ m P0 |: c
l_vaIndex.iVal = lIndex;. a0 a* M% C! ~8 H4 X5 b2 @
2 h: M/ D4 V7 [ t6 l9 U // 取得字段值
6 w. V; L4 ]! V, S! l5 P varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
$ u2 T0 {$ b% i O }
+ ^0 \' c' {( ]- ^' b; q' d: z8 i return S_OK;, o$ q2 }( R5 I( _, {* b
}
' {3 O) w. e% O, r catch( _com_error & a_pComError )' k! D6 a1 J+ y. j3 n3 z: N. q9 ?
{
6 g4 ?1 E$ x# f0 k: {! } …. // 错误处理6 G+ O0 }4 r' C5 F; X# t
return E_UNEXPECTED;
; y' ?7 p( e: J( p, D }
; ?0 M' b3 T* N& ?0 F) H: i catch(...)
9 n, W9 E% q$ Z& O. @# R8 O% P% V {* L: n. r. [& G
…. // 错误处理
$ h9 c ^3 u' ?1 K* z return E_UNEXPECTED;- v: q4 h" C6 z0 F& B9 Z0 Y: z
}( G+ a) E7 u6 b6 s- N- _/ Q2 }
}
" R* ^* r' C( `2 }* _
, Y F9 r, v* E3 B+ t) i# U; e7 _. s; Z" o! p
7.出错情况下错误信息的取得
9 [) U( i6 ^% b! ]
& `. w4 l4 o. [5 m( h4 t( Z! d7 r/ [void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn ); q$ l6 s7 ^4 ^
{$ P. C. Z6 }; I d. S/ @
// COM 错误取得
; ^4 q( z) ?) k8 x- l) K# @7 Z // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
2 Y8 R5 ~0 U5 q1 w; `7 O char lpComErrorStr512];+ l1 s5 l( X4 T8 ^2 O {, r3 T2 |
5 E; d- i) ?# X; K
sprintf( lpComErrorStr512,
) [8 x: q/ F$ Q' C' e4 L2 T6 A1 y "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s "," e9 j/ r2 c" z/ ~( M4 m2 n; O
pComError.Error(), // 错误编号
% h0 K1 v0 l, e o+ Z9 y pComError.ErrorMessage(), // 错误信息
; W6 V8 s/ f' n( k5 M" s (LPCSTR) pComError.Source(), // 错误源
1 [, M3 \# v6 N, \ (LPCSTR) pComError.Description() ); // 错误描述
: w3 C" P: W( ]# w9 S& B+ C
8 ?0 k" f+ k5 b" p+ h* V+ u0 B$ A // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息+ M- s& }7 M( j
// ADO错误取得
, W! `7 b- R/ P
$ o& u7 ~3 U5 r ErrorPtr pErr = NULL;9 O! B {9 S, y! x
if( (ptrConn ->Errors->Count) > 0), H: w# C1 q" Z; I( [
{) F9 i4 N @/ n f( @% m
long nCount = ptrConn ->Errors->Count;- P4 Z9 e o4 M- P
for( long i = 0; i < nCount; i++ ). R1 b+ H U7 U/ j2 V
{5 ]( V& b' Q; s
pErr = a_pConnPtr->Errors->GetItem(i);2 J p P8 ]' u; M \
+ ]- E% A, X; V char l_pchErrorString[512];0 U/ d* M p/ E% T' l
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",) X/ u) v4 D8 n5 q
pErr->Number, // 错误编号2 V$ j4 I. f5 O! N' r1 f( T
pErr->Description ); // 错误描述% i/ C+ B" T) X- p9 k0 J3 W/ c3 e
}5 X. { u4 d0 Q4 i, s
}5 p9 _- x1 J* P( u
4 \! b6 r( H* w
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
% R; c. b' Z/ v5 T2 p1 m- d // connection 对象取得错误编号和错误信息。 |
|