|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
S: \7 c; a& F7 q s& k) t- v( u6 c t1 V
1、 用import导入ADO 的 COM 文件msado15.dll) i2 x8 b/ s; F" X5 c$ u
3 r% s0 d/ q% S \: U
例如:/ N4 r0 [* {# D" N+ T- u
9 p* S( M& ~. [$ L0 m, y# C9 S #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
1 k# y1 \/ t( Q5 D
3 G! P1 h, ?$ ]- T, K no_namespace
0 [, Q% C, R( r- ?* r( f9 C2 u/ A, N2 G" | N
- {" {: ?( V5 p+ @! |
2、COM 使用时初始化
" L6 k- W" V' Z, t$ P7 ~: Y* H: C7 J
HRESULT ComInit()8 N' U/ q% a( ]( |; b; a- i
{ 4 A8 g' k6 q+ Q1 B2 r" U8 }
HRESULT hr = S_OK; // 默认返回值4 S3 c, y' Z9 w% Z& y7 R
if FAILED(CoInitialize(NULL)) // COM 初始化调用
' E; r4 {* S8 h4 h0 D4 R7 J {/ Q( ~+ A2 B7 g
CoUninitialize();$ P' }* |5 U3 Z; r1 p2 [
hr = E_UNEXPECTED;2 z) p/ y9 e; ^# ^ m4 ]
}$ S$ r1 M( u3 c+ v2 J
return hr;1 u+ p# T' f# f; @* F1 l
}9 t" f9 a1 \% e+ L$ m$ h6 ~
. b3 n$ S; w4 `7 b7 Z" G- N9 f- m# v: ~
3、建立数据库连接
; h: s7 J. h' T! }& Y H
1 Q; g( d2 P; ~! @# RHRESULT ConnectToDB( LPSTR pUserId , // 用户名
# Y+ O8 u& t, s3 d LPSTR pConnString, // 连接字串
$ y q: V6 F( r2 j5 C) r: t2 { LPSTR pUserPassword , // 用户密码
0 K4 i6 P3 }2 y: k5 \ ConnectOptionEnum ConnectOption ) // 连接参数
- ^' }1 V9 R$ Z M: ?{
3 p1 m1 \6 Z. s7 @8 C0 E7 w M8 N6 w' C. X2 `( a
HRESULT hr = S_OK; // 默认返回值: ~) c5 N" I$ R' @
_ConnectionPtr ptrConn; // 定义Connection对象
# @& k% ^0 h, Y' T5 b V5 q4 C) _8 A, u6 K
try
B3 B# K- N3 X' g9 R. [ {
/ s( E0 d a0 u$ [ // 创建一个连接实体! N) _5 D% N; L7 F$ z+ U8 E
hr = ptrConn.CreateInstance( __uuidof(Connection) );
( ?3 x/ f# C5 y q# f# M7 i9 a- f. A& R# ~" W3 _& U
// 设定连接等待的最大秒数,默认是15秒
% A# X$ s9 M" e5 S' C5 M1 r ptrConn->ConnectionTimeout = 20) @; U3 d' I& T# p) K2 I/ z
3 ], L8 K5 F: b Y4 z // 打开连接! v: x( q1 U6 U* D N( I
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );" T- _2 b% a7 i- b
return hr;
0 _8 J/ j" Z3 z) ~) O* D }
7 k" N" ^- T7 R% I' S. w catch( _com_error & pComError )' S4 @: [0 @ r5 |9 s
{
0 ^/ b# M/ q" p- p% q+ K2 X- U( A …… // 错误处理
6 i. d# @, A' Q: S. R0 { return E_UNEXPECTED;
( _- v; c+ j) M4 r+ z B3 l }
2 H; Q8 U) @1 A$ K" A- A}
% t4 r! r5 ?7 y1 V
6 ^; h: Q* A# @
$ W* Y) ^0 X* V3 A' Q) e4.执行一个SQL 查询,得到数据集(recordset)
( c5 K, M; o: L/ o% z# |9 R. i, ^: C* ]; p J- {3 C# c
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )+ m- w+ w8 Z8 W, P7 |
{
( g3 _6 e" P3 R5 v1 ] try
9 v2 f1 z% f \ L, U9 w/ o& _ { z& r% M! ?5 M5 `( C: l
RecordsetPtr ptrRS; // recordset 对象
9 c1 g' E) r$ S/ T% S2 C
( }) n- G5 Y) N7 v // 创建recordset 对象实体
! }' D( l$ [9 |9 U \ ptrRS.CreateInstance( __uuidof(Recordset) );. D" I$ }8 y) M1 ?/ j
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
2 ^+ {2 b; @3 M+ ~adLockUnspecified, adCmdText );
6 H+ u* }' X4 [0 e, g' Z
1 j8 F; e+ v W5 E- R 或者
% T& R5 H( x+ N, l! Z) S ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );$ ~$ I6 [( Z" l1 ?. j; I
return ptrRS; P/ J# _5 _% z) G( O' b
}$ g+ H' y8 C) E' h+ g ^9 |
catch( _com_error & a_pComError )
" @9 X3 y+ V, C) ` {/ o5 w1 y5 g' E% l2 e' V4 c' Y
….// 错误处理( B3 v, Y* C+ [2 j
return NULL;
! c) t* V8 S% I }
# t+ N5 k* c* g2 k4 E1 \}
. x% ]9 i" p; h0 }& m* Z
0 C+ y" k! n+ n+ {5 E# M
% b3 x7 Y/ J! x) W( v5.通过数据集(recordset)得到列的名称
7 V. i9 J% E+ B* s- J# V$ Z2 H0 C# @6 }' R& I
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
) [* S/ ?: p4 J# l) } char strColNames[][255],8 {3 f7 ]6 q: t) G
DataTypeEnum iColTypes[] )
6 r# I9 {- a4 z/ c) J{
/ E" x3 Z0 `2 V" U: J" k! ?% y( f try. p) B+ s# ]- }. l
{ // 参数变量
; o3 ]0 o3 `" } _variant_t l_vaIndex;
& t. V5 q+ w, w, n0 U
: m6 `- D, j6 {: O- | l_vaIndex.vt = VT_I2;: G- w) F- ? P) Y) x1 I/ M' X
* \+ m/ J; e- ~9 m // COLUMNS总数4 I+ }+ {. j6 N6 r7 f! W8 R
long lColCount;
- k/ t, O7 q6 F5 [1 H% S z, @2 w8 D
lColCount = ptrRs ->Fields->Count;. x. x) Y! l5 q
7 H0 s% I5 y" T9 H3 F& }) X
// 循环取得列的属性和名称
& ^. k) n8 L5 l8 L6 G5 o. P; S& |; s for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
- V1 b" ?5 w* r {
u/ L1 R5 |: k/ f/ U4 R l_vaIndex.iVal = iIndex; // 设置循环索引
8 C4 m& a, r- F: {3 J8 ~* t( T& } x' n& x" {
// 取得字段名称
; | F( g; K2 Q. [& p sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);, P+ u/ S, q0 K% a* F- {3 e
1 x6 M" B! R9 U+ h- ` // 取得字段属性
g& d3 ^1 e8 R2 R/ l7 E# [/ T+ |% ]3 _ iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
5 ]. B- {. b" I. s/ V" c }' j$ N0 K# W" B6 \( W
return S_OK;
4 K# u4 [/ `0 Y- N }" K* L! q& [% P& Q; [ |" x
catch( _com_error & a_pComError )
5 `1 S% C9 k6 W/ i; F+ x+ _& h: H- X {
% S8 \& | i5 I. n* _ …. // 错误处理
C. _2 J9 P9 w! X. V6 L }( | return E_UNEXPECTED;' V6 }! N7 l3 H- c) N+ V
}& _1 F9 J* [ r+ J
catch(...)
2 y B, m! @1 q. \ b2 ]/ x {5 I* E3 k. L, ~& b* g/ u. K) d
…. // 错误处理
0 } q7 Y) L, _1 B3 r4 T return E_UNEXPECTED;
" u8 |: v6 g! ?' G" Y5 _* B3 ]7 t }
$ h2 M# P3 Q& {* q, ^}
6 q- m4 c( @8 _# @1 j. T6 x1 q. B' ~( E t' X# G* r# p
% r I+ R- w9 {. }' ~: Z' g6.通过数据集(recordset)得到当前行记录
" v1 O! A9 p: I1 {
; ]& I3 G7 d" qHRESULT getOneRecord( _RecordsetPtr ptrRs,1 }) f/ B! I0 Z7 G$ {) q- n% p
const long lNoOfColumns,& z& r* _4 D' O5 T# o& Q7 A
_variant_t varValue[] )% N$ F1 W( y$ y) y. ]- K! f3 [
{
7 _( w. B; _ ]8 I. z try
3 h' S& B. n# | {
. d' @8 J3 y/ k' W! ^ // 参数变量. X1 P8 {( E1 w9 h# D4 I7 k
_variant_t l_vaIndex;
4 J! L; Z+ [/ z6 C& J* J l_vaIndex.vt = VT_I2;( g+ Q; t# ^. e! f4 L
2 S3 e; g5 ? R# ]' n! g // 循环取得列的值
r3 \/ k# d& V& _! H+ z6 J for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
6 \( c. ~* z" m- w/ h { , M; P, ^; u! x% x- j
l_vaIndex.iVal = lIndex;% [9 D, z' P, @
: z( V( l! p) D. @ // 取得字段值
; i0 t5 U/ v/ X) f: ?7 J8 l% d8 L varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
P$ z! j, b' I7 B9 j }
! |0 B/ n% U4 U7 p! F return S_OK;
! h# k# ^' z. {; n8 F }
5 j) e. Y! w/ I catch( _com_error & a_pComError )
" J& v$ P" ]& P {$ X _0 \: K# B* B# H
…. // 错误处理
, H a; H2 t/ M7 H1 C+ |% U4 w return E_UNEXPECTED;2 ~. k( I" g2 o' Z( ?* E( o% z
}9 s3 o* b/ E4 ^1 B( C
catch(...)
" j/ s+ O* ~& E( @0 j" ^ {
' z# Y+ K, t- K; W0 u: _ …. // 错误处理" T7 r& g& i0 X: C" u, x3 n+ u9 l6 |
return E_UNEXPECTED;' X' @* \. N2 E& e8 L# ]
}
' Q( b& W0 [% b2 D9 t}
1 u. H5 @: n8 R
4 _. h3 ]" N4 f+ C5 i+ k- O7 `8 v. x6 n
7.出错情况下错误信息的取得0 X0 M+ N' k% D
* _7 [1 W, b$ ` w$ s8 B3 Q
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );; g( n1 o; N- s i' X
{
# u2 p8 `2 l7 z4 e4 q p // COM 错误取得2 t4 d, b. r) } e% h* e+ v# Q0 @/ _
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
+ o2 C/ Z8 u/ c b! ^ char lpComErrorStr512];
- G7 z- D/ R- x% d) {- f& B, C$ D) K2 s( l& |/ R8 X
sprintf( lpComErrorStr512,
' \) [; a4 S: N, J* K1 ^5 G "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",
+ {* d/ W. `# R+ W pComError.Error(), // 错误编号7 x+ U0 b; x* p, O- l
pComError.ErrorMessage(), // 错误信息
4 c) F, s' Z7 q( K, n (LPCSTR) pComError.Source(), // 错误源
' B+ N7 S- m9 `' C1 ]2 O; f$ Y* ] (LPCSTR) pComError.Description() ); // 错误描述
" m. K) l( i. a) S0 _3 n% |9 t" a) e" c
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息' ]3 W( H3 \1 }- i2 z4 n
// ADO错误取得% d% v" o* [- ?
& [5 }3 g( f9 V% }. j9 Y( K0 i# F
ErrorPtr pErr = NULL; ]7 O! e- x: g+ j
if( (ptrConn ->Errors->Count) > 0)
5 h. f" [% o" I- U0 R7 Z! j {
3 i! K G) ^) ] long nCount = ptrConn ->Errors->Count;
8 w8 R0 w# y q# `0 U for( long i = 0; i < nCount; i++ )
Y8 ~' M) q& E5 q; @2 D! S( H" b, P {
& {& a- o$ M. W# a% s- X. @/ { pErr = a_pConnPtr->Errors->GetItem(i);3 D$ [9 n* F9 }- u5 n7 _5 E9 E9 K
8 L' }+ n* n1 D3 E7 K char l_pchErrorString[512];) x! R! |, r, V' q9 V) o
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",! @; \; u9 L1 p$ C" d- q
pErr->Number, // 错误编号7 T! m, k+ [8 V% Y6 a' l3 B5 v+ F
pErr->Description ); // 错误描述 ?* v X# c+ _& t1 j, D; \
}
7 \! z! N% @7 y% s) ~ }
* @" {" _$ z( E6 d: Q! l+ M4 V- f3 e+ ~2 S& W W8 x" p
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问 L' l! f9 _; b. J3 J
// connection 对象取得错误编号和错误信息。 |
|