|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
# R8 N3 h" \8 k0 E7 d1 n
2 x. Z1 t7 d1 W5 L+ j1、 用import导入ADO 的 COM 文件msado15.dll
& y" t3 z- v# F8 N9 P7 z3 B
$ v/ M8 k: s6 n+ S z! v例如:
. G6 F) E/ v6 r: u& L+ W1 W8 f; d- h/ r3 J- C
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\5 V) U7 Q, ~) @6 f
$ a* X0 n% }1 p* K1 z+ @* R
no_namespace( m2 J; T) _% t" l
& |2 z& s7 H+ u+ s1 x' k5 b
/ ~7 a; |, F2 d! X# H3 W! p2、COM 使用时初始化
% G/ `& b3 q g- U8 c. T
! c0 F: F& e" m% @% Y9 GHRESULT ComInit()* k1 I* M! T6 b5 X
{
! T: y* x9 g6 f1 Y- f, c: r6 b HRESULT hr = S_OK; // 默认返回值
3 G+ i/ O: e: Q if FAILED(CoInitialize(NULL)) // COM 初始化调用# X) [4 j- r0 }
{( ^5 z5 @' q5 |& @
CoUninitialize();( Z) Z6 @; u. x9 t' T3 G
hr = E_UNEXPECTED;
7 t" \1 p+ ^% w: E/ D; W! v }
. K. ?2 f% ~+ {* ] return hr;" ?. b, f3 k4 x7 p
}+ K* O. Z: l7 S
7 U0 c* J5 I* \/ U& k
7 M2 v7 \- e. @" C9 ?6 X- [
3、建立数据库连接
# P2 c" j* ^0 p1 Q
* v2 X4 k6 t; X( q, X0 q1 }+ AHRESULT ConnectToDB( LPSTR pUserId , // 用户名
. q5 g u( o1 V. R8 Z3 q LPSTR pConnString, // 连接字串 % ]1 C- w) K. f, a0 N& o, c
LPSTR pUserPassword , // 用户密码- L1 c& T' ^; s
ConnectOptionEnum ConnectOption ) // 连接参数6 L$ }$ F. ~. d
{/ A. p2 {$ G% B0 b0 Y, y+ G
5 q7 f" U* ?; e HRESULT hr = S_OK; // 默认返回值
- p5 V4 ~9 B7 J! d. ~4 ? _ConnectionPtr ptrConn; // 定义Connection对象8 j8 u; @7 C; k: {$ o
1 A$ K; s. R/ E7 T9 R try
0 W- W" Y. H. [7 e9 U* Z {
, q0 L1 M2 E9 f! \, Q5 c // 创建一个连接实体1 _3 n9 U$ j; l1 q. V3 E
hr = ptrConn.CreateInstance( __uuidof(Connection) );
6 P$ F* u4 M& O
6 |/ l! h/ f E) I // 设定连接等待的最大秒数,默认是15秒- j$ Z% R- Q4 V' x3 `
ptrConn->ConnectionTimeout = 20
6 G( S; O# T0 f0 i! \6 s
" V4 f C H0 O/ J' t1 L* c; u // 打开连接, a A1 u$ C% g3 ?0 A
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );( u% U6 a4 r8 ~) L) [
return hr;* A% s0 h3 p' Z6 Q# `. m( f
}. a- Q4 H6 x2 |
catch( _com_error & pComError ), Y; m) B0 E7 A
{
; T6 o" |4 S9 ~" @( j …… // 错误处理' e$ a' s) X; L2 r$ U. z1 ?
return E_UNEXPECTED;
4 j5 Y* `; N- g O; p }/ o/ M6 z. s, L; U; y1 F
}" T+ z8 y7 l* u- w$ r. D
! E6 M( M( [ P9 u w6 i
( ]% l+ e l0 u1 l+ v N
4.执行一个SQL 查询,得到数据集(recordset)
$ _! ?- q0 r; u# T; R
7 T, J' T# H7 D* M$ ?_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
7 [( n. k) e& K9 ~. ~{
! I+ y) X! L( n& L* x try
3 ~! G7 Y" A9 v6 H" K! e0 ] {
( L) R3 d, `, d* Q+ H U3 U; F5 Z RecordsetPtr ptrRS; // recordset 对象6 d0 E" _2 @1 _$ g
! z" c5 }& p& k; T5 A
// 创建recordset 对象实体
# {/ d, o$ [, Y x0 \ ptrRS.CreateInstance( __uuidof(Recordset) );6 O# s5 [% ?+ g2 Q* \# q
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
' } O1 C0 W f$ c* zadLockUnspecified, adCmdText );2 p0 t8 H, J! n" N) i
9 L2 P* N+ Q9 [) w) U
或者- F* l/ A+ D. \: W7 [
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );- m5 d6 h b' W9 o
return ptrRS;- j, R3 [1 l2 k& l- T% B( I( e
}
* d, h* `6 m { catch( _com_error & a_pComError )
; [$ i3 e. p3 O# B# b& Y9 n {+ U) g) `2 P m0 s) [
….// 错误处理9 N8 \, n% @; J6 Q" A5 e
return NULL;
) E& G% y7 K6 @: N }
7 e! g. {) L+ J( p7 R}
# w M& u+ J$ \7 }% i; x6 g! F* y: y( o1 W5 q! G0 S
: V& k, g U8 z# X2 O5.通过数据集(recordset)得到列的名称* P" @$ A: t# v' X' v- q. j
# H: @& k& F6 F1 v% t7 D+ v
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象0 V- U; O5 s! |* v3 ^) Z/ |$ U
char strColNames[][255],
- g7 \4 j- y. j2 Z5 Q. M DataTypeEnum iColTypes[] )) G: v+ ^5 r0 W- M- f# f
{0 G, k" D8 c( i6 n: a, p5 u
try- d; m v6 ^: q& `7 ?! v9 [* W
{ // 参数变量
, r8 ^: G2 v' t _variant_t l_vaIndex;+ @; T: w, l- a8 {. j3 S
: j" I4 t& F8 N2 v: ^ l_vaIndex.vt = VT_I2;: p- Z" d6 Y0 S' Y
8 i+ Y3 I! L% _0 L# y3 O
// COLUMNS总数
5 E/ M) h2 O8 t, T long lColCount;
/ r3 `2 p) \) K: [
% Z8 g9 F( P) _. i# X8 T3 l' O+ L: u lColCount = ptrRs ->Fields->Count;
5 T, O8 ~" A! M7 c9 p6 C2 t8 S7 q- S/ i4 J% b) r% D% W' [
// 循环取得列的属性和名称
9 g: I; g. W) z) _" A7 P( l% J& I for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
- g6 r2 y# t/ T' {9 w% w {1 o8 t2 c' b3 h& I
l_vaIndex.iVal = iIndex; // 设置循环索引. [" z. o- o) P) q
( n# J8 S% \! [. H, ? // 取得字段名称0 D7 N- o6 D/ ?' N1 X! B
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
3 f% C& ~" H+ ]+ V, y2 Q% H( B
& r7 f0 a/ x v o$ h9 Y K // 取得字段属性
% t! `# [* N2 Y( U5 x4 b$ G& @; g iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;$ V0 ^" L4 J; b& l
}/ Q4 z3 Q% s$ \5 S
return S_OK;0 L7 u% U0 ^5 ]% @
}
* {4 a' Q, C9 Z5 m+ v# k catch( _com_error & a_pComError )( W! p! Y; t1 K$ G
{
+ E6 S7 f% C$ y) Y# @ …. // 错误处理& x1 D% Y. _) c% \! S' y9 P) ?
return E_UNEXPECTED;
$ [6 u% y( |; E. A& g }) |2 J% h) H Z6 T
catch(...)" q g8 C6 x' W
{+ S4 c; K, ~5 X: Z+ q! i
…. // 错误处理5 H* q& J$ [3 {7 ^/ O" @! v e
return E_UNEXPECTED;& [( p9 _& ?# N f7 G7 {# @
}7 b/ I% p! }) F* Z% g
}! [+ C4 R w0 U& c0 R
, M$ ]6 a- q: N+ b3 g7 @4 k: I3 T2 c8 d# o$ f$ J6 d" |
6.通过数据集(recordset)得到当前行记录9 R' |+ k3 o# D8 T
8 o/ q+ k" `. c; d9 M2 pHRESULT getOneRecord( _RecordsetPtr ptrRs,
_. c' B( r+ }7 P. H const long lNoOfColumns,
8 ]3 X1 |" F8 |7 v2 d3 |! d _variant_t varValue[] )& l, Z# X3 r) ]( ^' z" O( _% h
{$ O- Q( K8 E3 e. L4 n6 K
try6 V' ]: j: U. i: J( V
{
, @# n: D8 M' @ // 参数变量
& Y7 G( A% f6 ^6 P; Y _variant_t l_vaIndex;
2 O) f- h, K5 P* m; M$ E l_vaIndex.vt = VT_I2;
( X1 A# |4 y) Y3 W! q1 t1 V# ]5 l
// 循环取得列的值! O0 x& m8 B6 Z/ w7 J
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
" X. A$ a$ }3 v! C) |! C$ y8 i/ y {
1 X) E- Y, P" y4 m! M. \# F; W) ~/ k& {& y l_vaIndex.iVal = lIndex;! u$ w1 K5 e/ ?) ~2 S
7 Z% }" J7 r8 |( R
// 取得字段值6 g3 N9 w z7 Y* b' E
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
6 p% b, P' f0 c! Z( g) }2 D) b! n+ S6 U }) ~7 z3 c: m0 |
return S_OK;
3 l5 k0 i9 {! ? Q5 P+ i }
3 X1 r* T3 r; j0 a+ K: I$ T catch( _com_error & a_pComError ), L) {: G2 G/ Z# @
{: s8 z' n% o# s& ~1 ?
…. // 错误处理
3 q. y1 O; C% ]6 ^ V return E_UNEXPECTED;
% {5 T% L9 v% N: Y$ ]0 a }
+ b6 q: l3 Z8 O% Z catch(...)
! w2 U4 e6 `' V) ~+ E& b2 f {% n$ z7 m0 a* ?
…. // 错误处理6 `; ~0 G" g- w
return E_UNEXPECTED;
Y( T4 h; y1 o V w }
n2 F5 s% T# Y) n; z/ x5 E4 P7 X}) |& w9 `8 W" Q$ b! G
* y$ W3 ?7 l0 f0 q. D6 F3 W
$ x4 `& n6 |; F3 o7.出错情况下错误信息的取得
8 _/ e& U+ `) T0 Q* o: E3 o
4 T) q, m6 S7 h3 \; xvoid ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
- B% X8 S5 r: p6 i5 K: V3 z0 `' h{
+ N$ l+ Y* d/ B // COM 错误取得
9 u. S7 O' o; I: J$ z // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常3 a+ l' Q7 Q* {) C' U+ G
char lpComErrorStr512];0 w, j$ Z' U2 [- I
0 d, x$ S1 I' a& j; P sprintf( lpComErrorStr512,9 i4 Q1 J2 l3 }: l5 t
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",
9 F2 N2 e& n' g8 K4 y0 e" f pComError.Error(), // 错误编号9 n) n7 d. w0 W# R
pComError.ErrorMessage(), // 错误信息5 z p0 G" X0 ]* T1 K/ w5 l* `
(LPCSTR) pComError.Source(), // 错误源
! D* v" K+ j0 X# Y* M- ^ (LPCSTR) pComError.Description() ); // 错误描述
5 ?4 C- m. d: p5 G1 K$ X- G! p% w2 N+ {
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
9 [3 R; {, ?$ T: ^ ` // ADO错误取得' e: F' U% u6 p. W& @1 o# J
6 i9 {. Y4 Y9 h3 j, E4 I3 ] m
ErrorPtr pErr = NULL;- }# P" s* K- i# N/ \; I [
if( (ptrConn ->Errors->Count) > 0)) O: D4 U' @4 n9 k5 i: ^
{
$ W0 D5 ^; d$ d0 S& g long nCount = ptrConn ->Errors->Count;
% Q6 H" V: T2 _; t% s* ] for( long i = 0; i < nCount; i++ )
# c, B8 h9 f2 r# s {
2 m5 `3 m# F6 E4 W* H pErr = a_pConnPtr->Errors->GetItem(i);6 M2 N( m# w$ F& U' Y
4 H0 D) p3 S) S* ^/ ~/ g, E* c char l_pchErrorString[512];
8 f0 X3 t Z" @ sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",; o. u8 h7 f$ n0 u: c- C: t8 D
pErr->Number, // 错误编号7 p4 g w/ E! x7 K6 B2 p/ r
pErr->Description ); // 错误描述
* j% Q9 l4 r, p }
8 W! q- ~; z9 B( C }; v+ A& @& C0 B# L1 {* ^
: e3 _* X5 I# `0 F* V, U2 } // ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
: s2 I& f1 N' v4 o9 y7 Z // connection 对象取得错误编号和错误信息。 |
|