|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
# w2 F/ R: m: s# V
+ h, K+ c5 `: r& o2 l9 a1、 用import导入ADO 的 COM 文件msado15.dll
@/ J9 k( R9 L
& x$ N9 E! \% H3 [* ?例如:# i9 C& j0 M @2 T$ b0 T% y
9 [% S6 W) D9 i #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
% O. g( ^& w+ L5 L
! T3 o( I+ f- H* h: J8 _# j no_namespace
& h8 i7 X3 `5 N9 r5 }2 d7 H$ V7 T( D) A% ]5 D9 o! P! K3 h
& X1 I1 _2 k3 {; B X1 p2、COM 使用时初始化
, |3 h5 _( W3 G) ]% u& l5 d6 |% B X& i) c( o( ^
HRESULT ComInit()' w6 l- Z! p' _8 L
{ / a: K' [% _/ ]" ^) P# W9 }
HRESULT hr = S_OK; // 默认返回值- a$ r9 {( y$ A- h1 L& a! v; e$ N+ Z
if FAILED(CoInitialize(NULL)) // COM 初始化调用
- [4 L( @* i( l: @4 | {
) j. K. ^. M% ~6 {7 n) F CoUninitialize();
. J/ F2 K4 F+ A; y/ D hr = E_UNEXPECTED;2 K! Y/ Q5 \! Z) W6 R: \$ C
}
3 k3 W$ P; y! m8 @- {& T7 p return hr;
5 z4 m- C" r) i2 {9 X4 ~}2 y7 e3 A$ L* b: @- t# }: G
! c* e. Y) Q+ L }- F3 q- J. s9 }+ ~* p- y9 p9 w) a
3、建立数据库连接& d. [' O; l8 Z
- n+ k& M/ s7 C0 u. X7 K+ J" v
HRESULT ConnectToDB( LPSTR pUserId , // 用户名, ]7 B4 A- |9 v* |) o2 u( H Z, S# ^
LPSTR pConnString, // 连接字串 % E1 P) c9 ^; O9 q | P
LPSTR pUserPassword , // 用户密码# K+ q; L' {$ d4 c0 _& X! _
ConnectOptionEnum ConnectOption ) // 连接参数9 C+ k: |8 [' Y3 k* L8 |1 S1 F; b# ~
{7 o; F8 x3 L6 u: Z4 J3 j
" I* C( k' B3 i: i; O# ^ HRESULT hr = S_OK; // 默认返回值. [. z; c1 K. B1 d, F9 i
_ConnectionPtr ptrConn; // 定义Connection对象 u3 G" |9 q7 t; Q2 o5 V
5 E( M$ I2 j! G( U3 U try. K; G1 q0 N5 c
{% F5 v- _1 M r
// 创建一个连接实体# `$ _# F0 s3 f- s/ a' c6 h
hr = ptrConn.CreateInstance( __uuidof(Connection) );
( f) Q( t9 B* r
. I3 p" U! p0 |8 \# O // 设定连接等待的最大秒数,默认是15秒
( t! ` M7 c9 p7 `. j$ ]- r* n' [ ptrConn->ConnectionTimeout = 20
4 ]4 W- K8 h6 E. H; ~" H
, ]( _9 F- R9 y M, h // 打开连接' C( @: h8 W4 S- M. y9 j$ f
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );2 s- M. r) y" Q# p
return hr;/ ~8 \3 W7 S5 ]7 _( B9 B
}2 L( ~6 {4 ~$ e" r0 X! Q+ Q4 I% j' r& ?
catch( _com_error & pComError )7 U- Z0 S" v: D6 `* E6 `+ @
{0 K* U5 `5 N2 |4 u" O6 E
…… // 错误处理6 Q; O% `# X# H& M( u9 L
return E_UNEXPECTED;
8 v7 o- V( Y( b! K0 z7 ]' c }
x1 W1 {" m6 C) K& c}
% s3 {3 v' B" o# ~8 M/ R* y- @# S- J( u
6 a# Q+ |# C9 ~$ A9 s4.执行一个SQL 查询,得到数据集(recordset)* K9 L$ J1 X( `
k N9 g2 @& I2 Z_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
/ F3 S! y" k4 `# o$ g- l{
m+ R* @/ d% }% e try
& X- [* S8 r8 L* Z4 H% E {
4 e) [+ R2 D- F) K: |4 x/ P RecordsetPtr ptrRS; // recordset 对象- @ Q* Y- L$ p
L7 d8 O" y/ S6 e9 z& O" u5 L
// 创建recordset 对象实体
4 s6 |5 G. b. o6 o+ ~: P) i% d" ` ptrRS.CreateInstance( __uuidof(Recordset) );
6 Z7 h* w8 L3 k! B2 \/ O* x ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, 4 b% e( S/ c: N3 W. ?
adLockUnspecified, adCmdText );" L% \# I3 ^; o. `5 V
1 U1 o( R. Z& Q1 K5 {1 A
或者
4 ~ J. T5 K3 i4 ~, t ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
8 m( [/ c! y0 J# s5 y0 q return ptrRS;; w, W0 M1 g/ Q2 s. X
}3 {, R& Z/ g8 z! T9 H
catch( _com_error & a_pComError )6 Z% O9 K; H" l: |0 Q
{
6 r$ k# |) O- x; i3 R9 v# J ….// 错误处理
# T' c$ U0 k: ]( O1 W* r return NULL; i+ H E* ]/ f" H5 |% z" a
}
9 f. e' l, I& M+ v5 R% Q% G# z}$ C6 f! _7 L- j% V
, I/ A0 a# m: h1 ?8 Q
! \, Z7 c: P" T7 m9 A# Q5.通过数据集(recordset)得到列的名称" a% F! _) j8 c- @' D0 I
. ^8 l( N+ U& W$ J6 i4 Z
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
4 \% J$ v2 x+ h, i' ~ char strColNames[][255],
! I" T. S* E6 ` DataTypeEnum iColTypes[] )
; F9 t9 }" D! L. H+ }+ [{3 f& M) g1 O2 C5 r, L0 l
try
4 A/ r# U" w& ? { // 参数变量% v* W, p: b) E: H. v" R
_variant_t l_vaIndex;8 N9 v" _. M, r! R) w. a( J) a
7 Q$ _) [0 w2 C) ^; p- \/ ?* ^
l_vaIndex.vt = VT_I2;' i6 e `0 x% ~4 m9 m
, h b' w& m4 q: _6 O- n
// COLUMNS总数
9 H8 w0 O) e6 p1 v long lColCount;. |% S: |; _1 F; F m7 V
0 B1 R# l, E s4 E8 m( \
lColCount = ptrRs ->Fields->Count;5 H# b: ~0 k7 ]" }' Z' g( P4 f
) e1 g6 v3 m9 X. M
// 循环取得列的属性和名称5 _1 ^8 i9 z% J1 O! Y# d9 {2 d
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
$ b3 q& f O# h/ v" [0 C2 T2 N {
: j' h; V1 M' i l_vaIndex.iVal = iIndex; // 设置循环索引
5 W, v4 c P! s* [8 V0 j7 L% u. z
// 取得字段名称
* E2 k3 H% C' b7 c3 Z/ l sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
3 f3 R& ?% i% l! ^
% [7 K$ u; H, Z0 E" Z. ^ // 取得字段属性3 v1 U$ l- D% s" T5 t" u8 s
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;0 a% K: ]9 k5 v7 ]5 H$ Y
}0 Z& c6 m6 r' v6 d$ m3 C/ _
return S_OK;
; u& _9 J$ i' S' K }
, A |7 Q9 F6 D9 F* a3 R. J catch( _com_error & a_pComError ). E, J- |3 H/ F# ]. K4 M9 p. I
{+ ?0 q4 b4 N9 o4 x1 `* ]; ~, E9 c
…. // 错误处理9 b( o# |. ?8 l2 c
return E_UNEXPECTED;
7 S. ^: N$ Q+ C8 W& ?. X% l% H }: A) F* V e) |6 ^& r2 l( r) F
catch(...)
; D0 Q0 a/ L8 |$ M) A$ v {" ~8 z0 o, a. \' W: q3 v% q
…. // 错误处理# P& e' J" Q5 T7 Y# V( v8 K/ d$ u) M
return E_UNEXPECTED;
' u8 u2 c) U( q$ e& z+ Z }
% C4 @) o, W! C; c: R" ^- K}
4 M8 |4 I* |# ]" ]; {( j/ b7 j" |" H+ K: ]9 u \
7 i( I& [; d5 L9 A- X5 n7 h
6.通过数据集(recordset)得到当前行记录
; f( h8 E0 u# U
, @. ~8 o% d9 P9 G a1 rHRESULT getOneRecord( _RecordsetPtr ptrRs,9 ~8 h1 |( {& r0 _) x' n
const long lNoOfColumns,
' L1 J! K# t$ o4 z7 G9 l+ o% S _variant_t varValue[] )
! d, I& Q: f3 z" x7 f8 e7 c- Q* w{
& G! y! r2 n" b" ^, M7 w try
7 j# R v! U7 L9 n9 ~" r {
1 s! g/ x" i; Z0 n // 参数变量
2 i6 G3 `% z9 g; C" @ _variant_t l_vaIndex;4 L. j7 _: \, Q A
l_vaIndex.vt = VT_I2; f) n- ?8 C6 {& K% @' h+ [
t3 K2 X% C) ]
// 循环取得列的值
! a5 v! N9 p; r3 A. r" T for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )- T/ W+ m$ b% u7 @
{ 6 U, P7 l! B) s0 q& j
l_vaIndex.iVal = lIndex;( T8 ~6 _( u0 @6 r- P* p- G, z
/ o7 j9 X5 n9 b3 O e- Q r2 t
// 取得字段值
' B! i% P; Z! h varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;( l9 \; I' h& q& {
}
: h3 h9 X$ ~7 k! [ j K return S_OK;! }1 T8 m9 v- @5 n1 V
}/ C! y6 p' k* ]# J k
catch( _com_error & a_pComError )
7 }/ w' e, g' \7 J: ]5 g2 x {
8 u6 \6 u, Q% i" Z …. // 错误处理3 F/ V) v* R7 M# \8 P3 g
return E_UNEXPECTED;
% C& b1 b ]/ J0 E, F5 l }
* u8 p) W1 y5 ?3 f catch(...)% ?: k1 v3 _' U/ p9 E& L/ ]$ t- f) W
{2 m7 y3 w3 [" ~. J
…. // 错误处理& t9 _4 g9 d/ i/ k2 a4 i$ O
return E_UNEXPECTED;
. | ~3 x1 ~% } }2 a; {+ v4 a7 n( V
}
( x6 x% t% g9 T) b+ [
+ s& x3 j% U/ u( ]8 R; L! D, A1 ^! x8 B3 @
7.出错情况下错误信息的取得8 \9 H* ?5 y0 M. g5 k8 o
7 [7 a( }+ l. G: ^( u; k
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );$ r" g6 f. c* @ g' q0 o
{9 ]! u2 }( x( _0 y) E. P
// COM 错误取得) }+ J' h% g) i6 T7 U
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
# c: F6 B0 t W/ H9 ~! U char lpComErrorStr512];
# k. O9 H+ K: s9 u* X" M% F; q" e- L" ]3 \
sprintf( lpComErrorStr512,' E* p" H3 d" C; v' [
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",' v- O) q k( h+ Z9 Z2 \2 E' G8 o
pComError.Error(), // 错误编号
( |) g7 d4 F0 J* }% k2 q M: n8 z pComError.ErrorMessage(), // 错误信息/ M+ D1 m/ o u+ @. l9 R' Y
(LPCSTR) pComError.Source(), // 错误源
* q' b$ n2 g x+ ?; ? (LPCSTR) pComError.Description() ); // 错误描述
! v$ M# h7 n2 q h+ }( u3 r( ~+ N! S( I6 ^3 |
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
8 O# o# f; t6 G% f% y // ADO错误取得% v" V! j# {5 d3 S& y
/ h; r0 c6 j- D' w- d' R- @' j! F V ErrorPtr pErr = NULL;
$ G' E4 m" K& w/ t' Z; V if( (ptrConn ->Errors->Count) > 0)
3 Z+ x m. y+ C9 q' k1 a {
. x1 e0 Z- Z" o# @1 q8 |7 [7 f long nCount = ptrConn ->Errors->Count;
( T$ u/ |" u$ s: L- n for( long i = 0; i < nCount; i++ ). t' p1 g( r, ?* `6 r( x6 m
{
: v o. ]% B! M5 b/ {) { pErr = a_pConnPtr->Errors->GetItem(i);' V. u( ^8 Q5 w2 k# U; v3 b6 A
$ r' \' r/ {: |) Q; F char l_pchErrorString[512];
' n0 i- a$ }% |- y) J" q: V/ b sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",$ ^/ \7 b2 a4 ^8 S. `. i
pErr->Number, // 错误编号7 N5 a8 r1 b5 c( [6 Z5 q' S/ y1 C
pErr->Description ); // 错误描述
! d/ {1 T* J- X7 e, H6 u9 t }
7 R# B; ]- t9 O7 P7 G7 k' x }! s$ d9 q" \4 c @6 U
% w8 \# f0 e9 T" d4 Y
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
- C T% v& e* t! _ // connection 对象取得错误编号和错误信息。 |
|