|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。4 |4 \! i: _$ A- H- X, n
$ D _/ M: `0 v( g
1、 用import导入ADO 的 COM 文件msado15.dll5 X" |+ h V4 a; Z$ K- W' J
, y2 ? e6 N1 G
例如:3 m9 I( G4 J& N
+ C, Y# ]- Q* `
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
2 T! f; V# h/ L- y5 ^) r9 |, p- X" ]: O2 O5 C$ V: z
no_namespace2 U& c& m! D. s* h) H7 J
+ k! }7 _9 q# g! G! M3 V" @, H4 ]- X( y
# @2 r$ ?; q* b! b g, f2 u) `
2、COM 使用时初始化
6 [0 {( Z6 Z9 X1 z2 l* h8 }8 G! S* Z/ {3 F5 l6 T7 z R1 |0 O
HRESULT ComInit()1 ^6 W: u R: L: U9 P: L& D7 |
{
- f9 S r! A. P- N HRESULT hr = S_OK; // 默认返回值" Z$ e! h- k% g! A1 U$ B2 }1 ^
if FAILED(CoInitialize(NULL)) // COM 初始化调用
* c# O* a* s7 a9 `) f; q1 P5 c {
& c" `( n+ w V6 r CoUninitialize();+ [$ h' @# t1 i4 I+ `9 p4 x! Y
hr = E_UNEXPECTED;
1 p# n6 `% Q7 r }
; m0 [+ c1 J5 B0 p6 z return hr;
; a) k$ T5 _/ i- g$ u6 |3 Z}* F C) I B7 v( `( s4 f4 ^
) l, Q% k7 W* t" O7 X& R) @% o, j) I# t/ M9 V; c
3、建立数据库连接
) e! m& l" I8 N6 o- O
+ B2 P* n( m! d. sHRESULT ConnectToDB( LPSTR pUserId , // 用户名) C# j! G: N/ \/ M$ F
LPSTR pConnString, // 连接字串 # |8 q! N# ^, L3 R! L& U" Y
LPSTR pUserPassword , // 用户密码
8 p4 M2 |& ]0 X& x. K% ? ConnectOptionEnum ConnectOption ) // 连接参数* G" h% \0 S3 w- q0 E! G" |
{
4 E0 ^0 R! \' J+ A. V
+ u/ S; O2 q* \) j HRESULT hr = S_OK; // 默认返回值. ^9 u- L/ {0 Q- `, b$ V. m* ]0 y
_ConnectionPtr ptrConn; // 定义Connection对象
/ _# H6 I% K$ ?! d' Y3 W1 A3 e& ^$ X9 l
try: |4 Z! Z0 [- A# w; m! ~
{+ q, G9 W6 c' T. F
// 创建一个连接实体
+ ~/ N* F8 o3 D; Y$ Y2 q3 a hr = ptrConn.CreateInstance( __uuidof(Connection) );, v* W c0 C$ t/ A E5 t
# i7 A" C( f& F) y // 设定连接等待的最大秒数,默认是15秒
7 R( d, w+ `" d( G t; k! [ ptrConn->ConnectionTimeout = 20
( n. |0 t8 Y8 h5 M
: [! m! t9 G: k- ? // 打开连接7 z" n2 o0 F* e6 \
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );2 N. ]; z' T8 Y( ~2 I; X& `
return hr;
1 |, s: S" h& l1 g. p9 A }
$ y. @, C% s" p1 K# A2 I1 m* Z catch( _com_error & pComError )
4 o& \+ y! h4 u" e5 B, T1 y& u( q! Y, y {
& r5 o& u+ C- Y' o. f ~; H7 c …… // 错误处理& N+ U- L6 a" y+ M) N
return E_UNEXPECTED;+ G) b9 j: f5 ~! |, X& R! p
}
7 U V: D) }! Y, h4 ~ Y; q}
0 T6 B- j5 N' H
* j: Z& x/ a( ?0 u- S( R
; [6 n3 W7 b' @$ H, {3 R4.执行一个SQL 查询,得到数据集(recordset)5 |" |: o! Q1 m& E. `
( V. y4 y5 x3 l
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
1 x. b2 O! p& O1 j; o- v{
1 }5 B4 f3 y2 K- P' M' }1 W. F* g, c try
2 m0 }! w8 l! r; b4 G {
1 `9 b8 h7 Z, h) V7 { RecordsetPtr ptrRS; // recordset 对象
+ E5 @% N) h1 l, z0 {; _5 E" F* H0 D& E+ v, l
// 创建recordset 对象实体
+ g. t2 D" |0 e* h1 Q0 X% ~6 v, e ptrRS.CreateInstance( __uuidof(Recordset) );
1 H5 T& A, X5 z5 x, _( t t/ d |4 t ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
9 Q, \/ p4 |9 Y4 m; padLockUnspecified, adCmdText );2 @7 W2 e$ Y( X2 f( M% [ q8 U
1 x k3 m1 G; [9 [
或者; X* _0 k6 Q ?" m, S
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );! e" c: D% N( G. U- O# u7 }
return ptrRS;
9 o) ^ K8 Y5 v. J: \: j j4 U }
/ v/ r7 z* q8 R$ }4 b" t; H J catch( _com_error & a_pComError )
/ F( ]$ c: E! ]2 A {
# p# v2 d2 I+ \, v ….// 错误处理2 T; X- b' Q& X8 S1 g3 q: X7 m/ `
return NULL;
, m1 N+ I# K5 m* E- z! S }
* Q- ~4 n2 `1 W3 b}0 q# G* g; V# Z5 S
7 t& j4 I4 }9 m
+ a) x$ y+ z" g
5.通过数据集(recordset)得到列的名称* u4 t/ z; |. ~! k. Q5 f$ ^ G! v
! d; r6 A d$ ]' RHRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
3 \7 R+ J" A- E char strColNames[][255],
$ c8 u! n/ B3 o$ x: T2 A4 M DataTypeEnum iColTypes[] )
8 w$ A& G" B9 i; Y3 Z; V! l{
0 g/ b) R$ ]) j) L$ D try" t4 t$ k# V R9 x e! i% N- Q& w
{ // 参数变量, c1 d+ w& w& f# u
_variant_t l_vaIndex;
" e0 P: {6 U- B# z1 I5 r
! c% ^" q+ g) b8 y9 t# j l_vaIndex.vt = VT_I2;
$ `3 ?# r1 L- E' @! G5 \4 k! n; V7 F- m
1 q4 }3 o- q- k( }. o- e$ M* B // COLUMNS总数
" X5 |, n t# z! V' B2 B long lColCount;
& p/ W$ ^4 i) P; I; Q5 e' _ T0 l& a+ Y, T8 p
lColCount = ptrRs ->Fields->Count;
1 A3 e4 |! `4 Z; K) a# H8 c5 R# i" q5 H) h
// 循环取得列的属性和名称
9 Y- W: s( X" x" O3 O for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
% C' @# t9 k3 p; V( Z7 [ {8 b+ O& ]% o5 \# v% x- O6 I
l_vaIndex.iVal = iIndex; // 设置循环索引
. ^! n! u3 e+ ?: I' e* f& X# n. f& r* U0 v( q
// 取得字段名称5 L# R" G7 V' V2 G3 P1 {% J
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);+ c" z D0 O$ u0 ^5 F$ l" E+ O2 u9 h
* c4 g0 B' J& q; W) b
// 取得字段属性
% ^, P; i$ w& x) m3 V4 M' a iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
2 W! c# H5 ] t: N" w3 \. g }
( n+ y: e0 v' X- p* i* X return S_OK;% C1 P- U$ T' p0 z9 ^1 p0 U
}, Q) ^( ?5 v4 L( ]% Q
catch( _com_error & a_pComError )
; `# M v6 V& W% i* K3 a {
6 s7 K% P) ^ _ t1 G …. // 错误处理; |3 |2 \- ^ a2 A" V6 }9 K" { {0 ?
return E_UNEXPECTED;+ H6 x0 `) G, @: T% B" h) l7 I( A
}
6 ?: O8 y% }, i! S catch(...)
5 j. Q7 `& F" M- L {+ \! d4 _$ j, {9 \% v, t: Z6 `% h
…. // 错误处理
) M! [. r# F" }* i k- Q* O return E_UNEXPECTED;) I4 ?0 p+ Z9 a/ r$ A) Z
}+ S- i h$ m/ `# l% q" N: h% b
}
( _& ?9 W6 ]+ B4 u5 h' r H- [8 Y9 Y s2 \, P$ B4 {' ?& B
7 p0 q/ Z. A" z0 V9 N6.通过数据集(recordset)得到当前行记录. Z4 ~( k% r0 @9 z4 l: k3 P
; `5 o1 I+ n* X, h9 t- s
HRESULT getOneRecord( _RecordsetPtr ptrRs,/ |$ ^5 p8 I9 s/ U
const long lNoOfColumns,
3 h: t3 ?3 a& {( m! j _variant_t varValue[] )
% N9 c; |4 X. o/ A$ [; z, ?9 R{
7 c' V4 J3 O8 X+ ]' o. U2 V) F try. L% r, \! d$ E2 d( L
{
/ f5 U d1 {& L' N. d5 H$ Q // 参数变量6 o# M* L; M/ o" i( I
_variant_t l_vaIndex;7 j* S% X6 u% |$ b5 d7 j4 o
l_vaIndex.vt = VT_I2;
' X1 F+ z: L# C0 D# x. d6 ?9 o* v4 E o" G" |( z. N q
// 循环取得列的值
5 r6 U% ^9 J# s6 V+ b/ ? for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
3 d( b. f' J1 G3 D {
/ m$ j. R2 I8 p4 }7 Z1 F. C s l_vaIndex.iVal = lIndex;
3 ?" J' d' R F4 l; z
, j" y" D/ S- s6 L& _# u- C: G // 取得字段值+ u+ o. O( h; P* ~7 t: a' f
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;0 M4 Q2 y8 i: s" ?
}
8 Q$ [: y: c9 u& I- U) { return S_OK;+ G$ l' ~5 T7 }$ c
}
- r# }" @- r6 j& G catch( _com_error & a_pComError )
6 P$ w9 }1 X; L! C, u% M9 I/ A {9 g( l9 _. s3 g0 O2 R, S! E
…. // 错误处理! n( T( X! m' w, k. X
return E_UNEXPECTED;
4 m9 D+ W4 J9 U0 C: g# v! n, S' { }. y' ^& X$ L5 T) Y2 H
catch(...)) O0 H/ v# i! S6 Z" R0 X; ~
{8 W1 U3 R- o! F+ e6 g z
…. // 错误处理7 i$ p( r3 m2 ]- \2 h
return E_UNEXPECTED;. N! a& A' m+ H8 h/ y
}
+ M, e; t' G8 i( g}3 z: K. G, v( Q& m2 L" q/ N
; U( j! V" r! P4 _) O, S: y/ n7 u
" J. |0 A. Q4 I8 q# a2 }# z7.出错情况下错误信息的取得3 K$ q( d, J0 p" ^ l* H! Y" j }
/ D$ k4 v& t9 ~: S" l0 m/ o% l; h
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
4 I. @4 c3 M7 H' A0 Z{
8 u1 n, {- l. W: X! J3 t // COM 错误取得
6 U( p4 a8 v e4 j. @3 c. J, m0 F // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常) I" Q0 e; @6 S' _; N
char lpComErrorStr512];* ^. y$ P, k6 t
9 [" G. G( U0 L5 K% w) x6 Q sprintf( lpComErrorStr512,
, P5 w$ E3 r4 I% [ "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",4 f/ U7 b: s6 w: m9 @3 s# d- u5 ]( U
pComError.Error(), // 错误编号3 k1 r. k1 z- f$ t
pComError.ErrorMessage(), // 错误信息
8 Z( G4 {' h9 u, H4 d" Y (LPCSTR) pComError.Source(), // 错误源# P) O& s6 m" v9 E" G8 T
(LPCSTR) pComError.Description() ); // 错误描述5 W* E; Y' O" H# ~" F
: j- j) V- n" R // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息; S: O) m& x6 ^/ \% P
// ADO错误取得
0 I" K. K. P$ ^( P! E1 O) E$ d" w& ]* h$ I. i4 W \ c
ErrorPtr pErr = NULL;
1 B. \1 i$ u. r" s1 t if( (ptrConn ->Errors->Count) > 0)
- l' k4 e" F( h! T4 p. f {
7 y' b" [' @9 G long nCount = ptrConn ->Errors->Count;2 w0 Z' P& d# J
for( long i = 0; i < nCount; i++ ) ?. A& j3 I8 n7 h1 y4 V
{
) U9 h9 I: h* H4 y& h5 V/ ?4 t pErr = a_pConnPtr->Errors->GetItem(i);
7 |3 [2 c1 a2 V9 g$ n, ]: q1 `, U. H
! s- d- A8 W& p$ l- X7 L char l_pchErrorString[512];+ Z, s5 e- `1 u
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",( q, L7 o, l" I* X7 p! ?0 C+ X
pErr->Number, // 错误编号1 d, `( O I( G( \5 o
pErr->Description ); // 错误描述
: y; }9 |( S) O: W }2 k8 r" N; I7 d& i1 X
}
4 O# Z* B1 x8 M% G L1 L8 I# b; i h7 O+ Y1 j! c& F
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
& s. c! U7 p& d" U) H // connection 对象取得错误编号和错误信息。 |
|