|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
6 F0 R7 H- h7 y1 i0 V8 x' I4 Q2 y2 Z6 s& J& W- t# H/ z
1、 用import导入ADO 的 COM 文件msado15.dll
6 p y' ?: v2 c1 V) y# w
9 d& F- H% Z" G8 x' C) H0 T例如:
5 p7 N& z, Z6 l( a; M" g! b$ Z# {
/ t8 N' L9 ^, v7 F+ W' K' I2 [ #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
/ `4 e: h4 T2 F$ \/ k% s& _+ i
no_namespace
8 m/ F0 U+ b1 Y! k8 [' Q/ j& ~( {
b8 j! e0 R+ m0 Q" l0 d# K0 H% ~) j
2、COM 使用时初始化
8 h! f% W* x2 E+ `" D1 b2 K$ d! c" Q/ Y# U* @* N
HRESULT ComInit()
# H) Z$ u* B% _, I& y% b& y e{ - u! W7 o _1 Y, @* `: D
HRESULT hr = S_OK; // 默认返回值9 L1 F9 l3 y2 ~1 }0 m
if FAILED(CoInitialize(NULL)) // COM 初始化调用
" w5 G2 E7 w |$ H5 \ {3 Q+ z% w0 V0 _; y
CoUninitialize();
/ k4 Z* K2 d/ e, U8 [) p hr = E_UNEXPECTED;$ [5 j9 T, ]8 s2 i6 x8 \( \
}2 ]. ?; ^7 x3 i+ i
return hr;8 A2 X" d7 {/ D% W# t% C
}2 x; G+ V1 \# f0 z* K& T5 L. [( j8 H* M
2 x, q3 E) g8 `: y1 ]/ L6 h* E6 ^( }% M' @2 L5 ^$ A" M6 } Z4 w
3、建立数据库连接' i6 Q% F+ ~8 F2 y. Z* Y
) e& T2 h* e/ C& v6 }8 bHRESULT ConnectToDB( LPSTR pUserId , // 用户名: O6 @) j; G$ D$ R9 U3 W
LPSTR pConnString, // 连接字串
. J& z% N5 p b- y8 R LPSTR pUserPassword , // 用户密码
1 X# `: c7 k, ^8 E# ^ M ConnectOptionEnum ConnectOption ) // 连接参数
5 n& ~7 p+ J X* g, E$ E3 j7 x{
1 J6 B7 f( a: e8 U3 U& R: e+ t
: ?& V& ^) s; r+ Y3 X7 Q HRESULT hr = S_OK; // 默认返回值7 t& x$ F& E5 ?5 Z
_ConnectionPtr ptrConn; // 定义Connection对象( `% Q# L9 q. {2 Y
# O. Z/ w4 h. q, X1 K
try
" A8 ?' W9 g2 h: o: Y8 y {: m; r/ E3 b/ J7 h0 T+ ?' b/ Y
// 创建一个连接实体
: y' ~7 ^! j/ F0 E. S$ g hr = ptrConn.CreateInstance( __uuidof(Connection) );
/ w X4 M" b& E) O: t& A7 q; ]
; F8 P% R3 V4 E; v ^ // 设定连接等待的最大秒数,默认是15秒
. Z6 Y$ D& ?- f* m" |2 f. p ptrConn->ConnectionTimeout = 20; x' b: i% |( \, y
# j" j: @5 y' M5 _
// 打开连接5 R. O" R+ ]( W' n e$ o; X
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
/ R# r9 F- U% ]7 |6 M8 N2 u return hr;4 ^6 Z# C' C2 H) R4 I
}9 `- D, ^2 ^+ o+ R6 J
catch( _com_error & pComError )
: q+ b, d7 X3 i8 x1 g! E1 ]# P9 P {% b1 f) U- R& b0 Y2 w
…… // 错误处理
! z% ~- M- f3 P5 {3 b5 W return E_UNEXPECTED;0 H4 Q* s0 M, Z) A- j: J
}6 }# R4 P9 j9 e) Q$ ?
}
3 T# D; X# d( [( D0 t3 ~7 q& P- y, _$ C
3 E7 Q: Q K ^# J5 O2 i$ x4.执行一个SQL 查询,得到数据集(recordset)4 m+ n; q/ v3 Q) Y- {
. z0 S v7 k8 d1 t4 A+ K
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
; k: V; N2 u1 M{, y( F& V: Z( V/ n1 ~+ W
try
' y. O) @2 ^2 N# W4 b; H- C+ P {
! B/ c& h# D- M; { RecordsetPtr ptrRS; // recordset 对象$ A6 d5 E; J9 x2 q* Q! n2 y" A
$ c4 C3 {& B6 C
// 创建recordset 对象实体. U# o9 p9 T, v+ |' Y+ }/ ]+ s; J
ptrRS.CreateInstance( __uuidof(Recordset) );- g8 p) |0 I# J+ y# }4 D5 o3 U
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
2 V- z2 s3 W, W6 m- m: f% V6 cadLockUnspecified, adCmdText );
" S- o$ W# Z* Q1 F9 G; _: N
# Y! R+ Y* E2 V, k( e3 Y( D& z 或者
5 b6 M) w% _; |6 N: Y3 t ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );+ I, E2 l/ O" p
return ptrRS;
2 W e2 p! i6 j2 | }
2 L' M. F% t: b4 \* A catch( _com_error & a_pComError )" ?$ C& ^% Q/ M5 w2 o6 ]. I+ j
{( p8 T0 e, N4 i4 i5 k
….// 错误处理; D" F" s5 [. S) ~' v* k
return NULL;
1 R" |% z, C: p }
- f4 _* a- _" I. a}
" i+ K" h0 G1 k3 f( f7 b8 w; E' X, U
, Y Y+ z1 N8 {" R) E; t
5.通过数据集(recordset)得到列的名称
* l# m& Q1 S7 ~
; K \, p. Z5 r, U8 ?" I- }( EHRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象; g3 {& H, t: w) |$ V
char strColNames[][255],1 C/ \1 r3 l* W/ R
DataTypeEnum iColTypes[] )
% f# O2 m8 w; y0 ?( X{( x) d, \3 H4 q
try
! F4 l) N+ i! V/ q; } { // 参数变量# V5 ]+ b7 ^0 r
_variant_t l_vaIndex;
- d2 ]! c% A8 K* W, C4 `
5 K$ E2 Z% G/ L: R3 ~6 P% Z+ Z l_vaIndex.vt = VT_I2;
4 H. b0 }) n+ r6 H+ ?* ^" D: C$ F, ]: F3 ^8 m% K u4 u/ j5 v
// COLUMNS总数3 R* q' Q* g7 B- V7 H
long lColCount;. L; g, J, |" ^) o/ ?' ~3 q
- n6 G$ V1 P' w) j! t! u9 `3 b/ T lColCount = ptrRs ->Fields->Count;3 `, g9 ^( z9 L, q; G- d6 P' l
e0 Q5 M ^) Z" l0 E5 p- I // 循环取得列的属性和名称
0 F+ E+ B# d8 c# t7 b0 J. ~" Q3 H for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
0 E+ _# w& `4 E j; Q {3 F/ J1 _( y a: D) ^
l_vaIndex.iVal = iIndex; // 设置循环索引
5 g- @) M4 Y; C3 a3 K: R$ l' u8 {( F% Z
// 取得字段名称& f: X& D. k2 f7 ?1 D! ~( y6 U
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);% o+ ]9 p/ U. i
7 a$ i1 f0 e2 m3 s+ m0 y- r
// 取得字段属性
+ S9 g# V7 C& O. p( }7 `0 U7 D# \+ H( f iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;+ f' Q- [% ?8 l3 s% x4 w/ {8 p
}) L8 Z# {. K& T) w# ]7 J
return S_OK;
" F2 q: p' \7 v+ R. E8 C) ^ }
* J; N ~: e4 ^# |; W catch( _com_error & a_pComError )
/ n! f! T' X$ m+ Q% X0 Z {, H3 m& h3 y$ {8 s3 r" j# F
…. // 错误处理
2 s+ b% p4 F/ L8 i# _ return E_UNEXPECTED;
7 z5 C$ G# k7 C0 r; {0 v: _ }
& D3 R/ Y7 b9 D( Z: |8 A. [ catch(...)
8 f7 x3 f; C9 X$ z5 _ {
! m- C. ?* x5 y- G …. // 错误处理
+ @: }. P/ a8 K4 u5 H; X return E_UNEXPECTED;4 H7 \' {, J( ^5 N: d7 U
}
! F4 T! o3 g0 b3 [4 g: c}
3 b5 g3 @& o% [0 s: U1 w9 R" n% k) ]4 {
1 s1 z6 W5 ]( [: y, A6.通过数据集(recordset)得到当前行记录+ Q" ~2 j l, W: H8 G: P
2 N/ W, k6 I. }# x
HRESULT getOneRecord( _RecordsetPtr ptrRs,
" y9 l# O; R" T; L const long lNoOfColumns,
6 n1 q& I" y5 S0 i _variant_t varValue[] )) Y$ d6 M$ C$ X$ j1 C% n/ N$ ~
{
o/ K, J2 U. m" _9 H# n try
) x7 z0 V. o0 ?" c$ U/ n {: [; u. }$ ~; \; x8 {' R" u) Q. B
// 参数变量
& y1 q7 `+ ] n1 i _variant_t l_vaIndex;
% c4 v/ E' d9 v; }* H4 }6 W0 R* `$ { l_vaIndex.vt = VT_I2;# D' J' c) L- p8 [& h: l( m
" x0 h4 B: G2 L( n* u! e, D // 循环取得列的值/ {6 p3 g, c8 p( H/ K _8 R+ V
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )7 x4 j+ d. j' s- K. j) g1 A' Y
{
/ F% n0 z! \. r0 J" `8 | l_vaIndex.iVal = lIndex;1 n9 ?! [7 Z# g3 J1 g4 X
8 s. B4 g' o" f* b9 `' P
// 取得字段值
6 O( s A8 ?+ v. A# A1 Z varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
Y X" J* }: k1 Q }
$ F+ M; Q. i' |, X4 b return S_OK;
8 S6 F" U. n- S. W }8 t/ p5 [: ]2 B5 O
catch( _com_error & a_pComError )7 [3 o9 P' {1 L/ w
{$ t: ]( z3 f# I( S7 {3 F! Y9 k
…. // 错误处理1 h3 Q9 U5 L6 ~8 U. l' L" j- @
return E_UNEXPECTED;
5 |9 Q& \1 A6 m! L( T0 b9 s }" H- a; k9 Z1 i1 w* V7 W
catch(...)" B! b) [- o" ^# h+ R9 x3 P! J
{& j# I; ]3 P' o( r) ^, m
…. // 错误处理3 `4 S: m4 R, N6 [/ `8 [' S
return E_UNEXPECTED;1 B b* J# j# m5 z$ b
}
% y& q+ E8 w- R}
3 U2 T( X0 Z& L5 D' M4 a, f6 Y5 Y% R* y
g. B1 l' C! K" Y' e g* x7.出错情况下错误信息的取得' R! b6 E! G$ k6 a8 t
5 d0 S. L; u% ^1 e; M! q3 j
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );) K" Y! k5 _9 y7 ]1 L
{
6 Y8 q1 S; R* @1 v8 K# n, l! ]! G0 X // COM 错误取得 T6 a% V0 b B6 o( ] O/ d8 P I
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常# f/ g7 P" P7 B1 G) v1 d% u3 h: R* X
char lpComErrorStr512];, @: m8 p& I# _8 x0 G, v
. S2 g, M4 i: b# E, G9 Y sprintf( lpComErrorStr512,$ \9 ]1 x2 C' F: O
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",
' y% Z/ M( o3 z8 ^- |. }! ^4 _ pComError.Error(), // 错误编号
' S: Y2 r, ^; X pComError.ErrorMessage(), // 错误信息7 Q( D& a* {2 J8 H8 k+ p4 r
(LPCSTR) pComError.Source(), // 错误源
& _; ?& z8 O, j; q (LPCSTR) pComError.Description() ); // 错误描述& @1 K$ ]% H% @( f
0 Y3 Y; a0 s' O5 M8 r+ R
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
; I9 I) Q. Z. m: Z // ADO错误取得! a: Q1 i+ g1 V( {4 w
# d5 q4 T5 Q8 X$ t# c4 B# X; M! n ErrorPtr pErr = NULL;
) `( \; ]* B7 X if( (ptrConn ->Errors->Count) > 0)
) V% G" p* X/ n! F) A! v {
2 k9 a( w2 P, a* S long nCount = ptrConn ->Errors->Count;
% \ I9 r. B4 ^' V4 Z7 N$ k# H for( long i = 0; i < nCount; i++ )) l- K% q7 d6 l; I2 q [1 f
{0 t; t* E% ~& z0 H# p m2 P
pErr = a_pConnPtr->Errors->GetItem(i);! n5 _. |% [. w7 G* m9 _+ b
; u) }& q9 y& l* n+ @6 F F! u
char l_pchErrorString[512];9 O6 m5 n) f8 ~2 |( a
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
/ W0 H/ v) T. _- b# i- v pErr->Number, // 错误编号
J; w- x4 W7 t1 K1 V pErr->Description ); // 错误描述! h+ ^7 r+ x' W9 ^- F3 _. \
}
' h7 j6 `+ c+ V6 e. k, e }$ ]% A* ~& I- j# z
. Q8 ~# r( q5 Q5 a" S- S
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问$ Z& e0 B0 @ u: z
// connection 对象取得错误编号和错误信息。 |
|