|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。 H$ |. d& p7 B0 m% [7 x
' G( f5 i5 ~2 X1、 用import导入ADO 的 COM 文件msado15.dll3 {+ A4 M$ ~& w
% B' S2 ]3 c* t2 |8 s, b, G
例如:
, w# @, D6 G) W8 X' n
9 p/ J# r) y4 n' g5 Q #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
& s( l R3 t# J$ ~+ p+ ]. Q" g0 h
no_namespace; S. {9 v/ k1 d5 x, e
3 T2 | x2 k z
# A- V4 L$ E" L% s2、COM 使用时初始化
, }% ~7 i# i8 Z( R
/ c& X1 y: s, h; kHRESULT ComInit()
/ I: W. o: a5 t( d2 {' a$ `( p{ / h2 z3 b! |9 m6 L! O
HRESULT hr = S_OK; // 默认返回值/ I2 l) m9 S' U
if FAILED(CoInitialize(NULL)) // COM 初始化调用 y% I) C: u) i; T1 S7 j# {
{
8 P. h; M( t. |2 T+ c/ `3 l' P CoUninitialize();3 }0 K6 P) H! H3 o
hr = E_UNEXPECTED;
" B8 g- D5 }7 C4 w7 X- p }' O& W# V9 v. e; u" @' w6 L
return hr;$ y* b9 `2 n, |* L
}; X9 C# M, R5 r% N
! L4 Z- ~9 e, W4 X. S+ L9 x1 D* A" X" A
3、建立数据库连接
/ [0 R2 ?5 ]0 Q+ }5 L& Y$ `
( D% H+ ^( T( F, @HRESULT ConnectToDB( LPSTR pUserId , // 用户名
( f' a$ ]/ S3 J* h2 f LPSTR pConnString, // 连接字串
; r ~# W0 B0 ], F k" p9 P) H7 V LPSTR pUserPassword , // 用户密码8 E4 q# A3 l, {- A2 M
ConnectOptionEnum ConnectOption ) // 连接参数
0 O" b) U" b! c( n{6 w# K8 f% `9 z9 v; @( s3 @4 E
: q. S6 H# B5 s1 G
HRESULT hr = S_OK; // 默认返回值% r" O8 n7 N! r. J E
_ConnectionPtr ptrConn; // 定义Connection对象1 R" J! h4 {9 \# N4 o" m
/ u' S6 m) Y U! l) Q
try
7 R7 N7 I) O x. I# ~3 |' u: E3 D {" e# D# F+ B) w8 a' F! t
// 创建一个连接实体
7 S' U! Q5 ~- g9 J1 w: ` hr = ptrConn.CreateInstance( __uuidof(Connection) );; r, R9 b$ {; C0 g- ~, c& W0 ?
1 R8 H* x6 F+ F# S M0 Q // 设定连接等待的最大秒数,默认是15秒( ~" a" @6 X" [" e% v8 t
ptrConn->ConnectionTimeout = 20
/ |9 \" U. M d P! k" R o) V) N
// 打开连接5 W/ ^5 m% A; A( Q0 S
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );! H" ]) }8 q+ T5 R. g0 B" G
return hr;
) e5 w! J. ?5 I( U }# v% V7 Q" a9 g/ A
catch( _com_error & pComError )5 H5 s7 v: ?4 H) O, t# V
{& Q: Y6 H2 _0 I0 k+ ?. J4 @8 d
…… // 错误处理$ u( N& V2 R% h# n
return E_UNEXPECTED;% N* J& F8 N5 P( g7 B8 f
}8 H' j+ f X; e- e8 n
}
r0 J7 X$ L. @' v8 u! \
( N+ T) U3 z5 s6 n/ J) l
' q$ N# ?4 \5 |: Y+ a0 s4.执行一个SQL 查询,得到数据集(recordset)
2 a2 z% H: k( X/ `
) G& W4 m& o: o/ k, _6 C_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )* C- M s# p" u; Y+ }# N. h
{
7 W! g. Q3 T5 S3 c0 X( a, a4 | try
9 c _7 v" @$ Y {5 ~" b& n w6 n/ z$ V7 Q, m+ k
RecordsetPtr ptrRS; // recordset 对象2 M" k4 I' a6 y: a: J
( M K- y: o; W% Q- e4 x: N // 创建recordset 对象实体
! {6 @5 w- c3 o! V, {$ F* M, @- l ptrRS.CreateInstance( __uuidof(Recordset) );) U- |" T: _ ~+ n! E
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, 7 F5 n6 c. { j; Q# J
adLockUnspecified, adCmdText );+ g1 n" w) [; D, b2 T
$ L: {% C6 \; S- f& |$ _. k
或者: a7 g% }; \5 v0 J/ G
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
/ `/ h* k! U+ M7 [) a" ~3 \ return ptrRS;
/ h$ K2 E/ v0 c h7 C- h, \" V+ N }3 ?! Z5 s+ v/ \1 o) q
catch( _com_error & a_pComError )" m9 Z K- x, z7 l
{+ W2 H; q2 y+ i: ?1 r+ j8 V
….// 错误处理 X6 A$ D/ x- Z+ e) j; u5 r1 s
return NULL;
. ]) F8 v: L4 J3 k6 o }$ G6 L$ w/ G$ @
}/ x/ V: \" [- U9 ^5 y8 U
$ @, @; S! r) ^ Y9 [+ R5 F' r! \' L a. b) z
5.通过数据集(recordset)得到列的名称5 Z, O! x( {8 x p$ h( W
; i( y) T5 B7 |8 R+ E( [
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
3 b% L0 C& W$ G char strColNames[][255],
6 {) \! W6 e7 O* w4 ~% U+ @ DataTypeEnum iColTypes[] )
2 o" `/ p) q- {! }8 A# d1 z [{# |' `$ j" [' z
try
7 \4 y8 _# L1 Z { // 参数变量
- E' n7 j4 O5 i* S3 J9 E9 L# C' \+ d _variant_t l_vaIndex;8 C3 |8 @5 @2 F; M- f
% S! \. {, o2 W6 {% B, L& C$ P$ [ l_vaIndex.vt = VT_I2;9 M) m6 _8 L; ^% W z" B0 \
$ \5 a F4 k( g. n // COLUMNS总数
* j6 p; }/ {( s long lColCount;$ y7 v! n6 p: y- {. ?
9 {8 n4 J; h8 V4 @; I5 J* t
lColCount = ptrRs ->Fields->Count;
K4 X B1 O+ r: W" h' V/ D4 D0 r9 g3 I3 C A2 C( O: s9 c
// 循环取得列的属性和名称, {5 b$ J" r0 f6 o1 h8 x
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )1 j1 o6 O5 k( G
{
; z2 B/ g0 U7 B5 B; ]1 N. u1 E' A l_vaIndex.iVal = iIndex; // 设置循环索引
" E/ y% E) I' u) n" k9 j' D1 p% ^
; K( E! A( s5 y& U: ?( J& \ // 取得字段名称8 p* b' i: L L: d" f# E3 y: [
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
* |7 X& p) F# A* d. j n( A9 a
& l+ F# [1 Q$ Y& Y4 a+ X! i: M: | // 取得字段属性
& \& N# W- E* c2 y' ^" b) P( y iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;) A1 M* p( {! r+ e
}5 C/ F: C$ ^: y5 d* t7 v8 n0 ^; Q
return S_OK;
" G+ V& W0 P, v! U' [ }& f* H& m' w* n2 v/ i3 E2 ?6 a
catch( _com_error & a_pComError )4 g' q! _! B" X. X& n3 [% _6 a
{
/ d6 e/ Q6 \# M5 [ …. // 错误处理
& r! m3 |) y* b return E_UNEXPECTED; D2 \9 q t# C- H' p
}" [ `: d) _( E7 B c) z3 _$ x
catch(...)
3 l; C* q4 B8 ^1 Z" Y [, E {
7 A$ t! P) h! f# q- E& w8 [" G% Z …. // 错误处理+ m: b+ M: u. Z6 y& P' n3 H
return E_UNEXPECTED;; c0 k3 n: M2 f! e" u8 S# Z
}. y. b+ l7 e8 b) C8 N" A# l
}1 D# s2 Y5 T; V ]: A2 X/ _: @
/ a9 }6 B* x9 q! L9 K# ~6 i* L/ f3 z7 D$ [
6.通过数据集(recordset)得到当前行记录
4 s+ c: J, ?4 q8 V; x: N$ F
9 m* o& ^; |7 p) DHRESULT getOneRecord( _RecordsetPtr ptrRs,& G% K1 }- K6 B' c
const long lNoOfColumns,
& ~* u" y9 H! x _variant_t varValue[] )7 y# q/ w( X" n+ b+ k" L
{
3 P5 H' o, B) _4 G) C try. K( O% q' |2 V; X
{& L) f* L3 T% L
// 参数变量
) E+ n( v4 B; x _variant_t l_vaIndex;
5 e- k) n* Q( v' `2 t l_vaIndex.vt = VT_I2;9 Z f3 T2 g* m+ v6 o! t" C
" x# c+ ?( H9 y- e; A
// 循环取得列的值5 ?0 _$ ?7 j# v
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )5 J' E- o- g5 }& \5 N# e2 g
{ - \! c! o% Z9 j7 y+ ^. A* ] [
l_vaIndex.iVal = lIndex;; h4 W, F- O0 W) a
* |! K* X* b! B6 G7 ]; S9 a // 取得字段值9 g7 i" N0 h3 H/ A ~5 ^/ B
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
O& i$ G% |3 a$ F# o }. n# y9 [# p; S8 J5 y! |9 b" Z
return S_OK;
, l. U; @, R& H+ v% O% F }* I/ J- M3 y+ x" P
catch( _com_error & a_pComError )
" v, e( \9 s# z" e5 z {
2 i4 o0 O; ]% O* s, h6 d …. // 错误处理
r8 [6 z r2 r) `) \) j* V( i return E_UNEXPECTED;
, h, q4 M: h+ e" Q" m }6 F1 k9 Q, [8 u
catch(...)* S" ^7 J3 O' M7 F, _
{
6 S4 o& U+ t! N% r …. // 错误处理0 F, v5 }0 E; K. I3 U
return E_UNEXPECTED;
, q2 ]) d3 O. v }
' ^, _/ q, L5 _# k* V( k}
. `. }/ P/ {. z x: N3 [
6 Y' t( q0 \- W
- e: l6 l% r5 O) ]: C7.出错情况下错误信息的取得
( S0 M( p5 q% k0 N: g2 T0 D" a9 @$ a% i0 V, X) D a1 l
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );5 H7 ]" g# s5 } k' l
{4 G6 M8 I1 Z$ a# Y( y1 N
// COM 错误取得
( z' t4 v9 a) ^$ C // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常$ Z/ ?& u+ p5 X( Z9 Q
char lpComErrorStr512];0 ]2 j3 r$ O4 m# U
: M+ V( K |8 y2 z$ o; S sprintf( lpComErrorStr512,
1 c0 k% |$ Z% [9 v& B "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",
% a4 m# P1 d$ G* i; i pComError.Error(), // 错误编号
/ F- H# c; X$ M" s/ B pComError.ErrorMessage(), // 错误信息
: i9 }( |) @5 V) K# X* N4 \0 G/ n (LPCSTR) pComError.Source(), // 错误源
; y" ~1 B/ D( B+ O" A8 n$ a$ S2 S (LPCSTR) pComError.Description() ); // 错误描述
, z4 e! j) X5 i3 \& W" e, B2 V( J0 P' X- r/ U: T
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息% { J5 t- X8 n9 `6 J4 `) D4 c
// ADO错误取得
# \: M0 d: @3 i6 E. X l
( v1 k: V6 K* g' J ErrorPtr pErr = NULL;7 `) y: S' {. y* e; n
if( (ptrConn ->Errors->Count) > 0)$ a) K: U, c/ o/ r1 n2 W$ d
{; f& r8 {1 M1 H6 J* z
long nCount = ptrConn ->Errors->Count;
1 z6 M& v) L9 @ S; x for( long i = 0; i < nCount; i++ )
* ?% h# W3 ?/ Y) n1 O8 Q. [+ S1 n# ] {5 W: i( D, n0 _1 c- G
pErr = a_pConnPtr->Errors->GetItem(i);7 L" x& I$ c% ]
F! u6 i. \# E i
char l_pchErrorString[512];
" v+ ^2 x$ q, Z8 V sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",0 [/ n* K$ f) Q% V9 ]' C
pErr->Number, // 错误编号
- A' z4 [% _7 L; i pErr->Description ); // 错误描述
* y& X0 A; F1 h# s3 _4 A }
0 E# C% l: I( ~, G' N }; D0 s% |( p9 X' {
K$ C3 \+ D. m
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
) q# N8 o5 U6 d; {+ i& l // connection 对象取得错误编号和错误信息。 |
|