|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。# M$ k9 Y' a4 B6 t6 v
/ f( n3 k" H6 ?
1、 用import导入ADO 的 COM 文件msado15.dll6 ^+ U5 N y/ H' z* N6 B- e$ V
/ c$ }7 n5 _$ {* u2 D
例如:
2 V: q2 f/ F1 N+ g: k1 D% G
& y/ s) k' K' s h0 ^ #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
, M2 l7 l4 F$ j- ~! B
0 m5 f# {# `( k. p no_namespace8 Y9 _3 x; }, J+ G! C
$ l) g/ M# `! v1 |9 Z0 F/ X
! Q+ d! @ X% M8 a2、COM 使用时初始化
1 K) L8 L$ r4 G
7 `7 Q( ~! l( U: S8 jHRESULT ComInit()" X0 \% a% v" V$ T* M- p* s0 A
{ / A7 x3 P# A/ |& S) r% X l
HRESULT hr = S_OK; // 默认返回值2 f) d! r/ [ O7 X ^2 W0 C9 V
if FAILED(CoInitialize(NULL)) // COM 初始化调用 @. a+ Q- d/ q; f \+ J! I
{0 `1 r6 n% i5 x" a6 W/ s6 @
CoUninitialize();6 C2 x% T) f$ I# @, w* b
hr = E_UNEXPECTED;6 R( F7 }+ F# |8 ~* h
}0 P* C/ B( b( ~
return hr;
) ?5 e8 |9 J+ u}
' p* a ]3 E# L/ ?# `: ]" l2 c
; r6 Q% V/ d) H& {7 ?" r) S8 S3 q4 C! N9 K1 E. _
3、建立数据库连接8 o% g* a% O8 i# l
; T/ c4 q/ }' A. ?HRESULT ConnectToDB( LPSTR pUserId , // 用户名, O6 Y2 _( H( J
LPSTR pConnString, // 连接字串
: i ?2 `2 s! M/ _% h, s LPSTR pUserPassword , // 用户密码
) N& J5 O+ \2 {% \5 F1 ] {, O- v ConnectOptionEnum ConnectOption ) // 连接参数
6 J' M6 O7 J0 J, D, G8 I: u' q9 }% w{
0 p5 |, f+ ]8 f8 u! ^
* F, P+ n4 i% g3 q6 j( H; V HRESULT hr = S_OK; // 默认返回值( Q/ q: j, B0 A$ B. c$ a$ G
_ConnectionPtr ptrConn; // 定义Connection对象% M+ a' t& V7 m
7 |- O: M" F1 r6 `1 T' u" z try' Y, R4 h j3 L6 [' W' ~
{) j/ R7 o& W& Q1 x2 E# f' D
// 创建一个连接实体4 y8 T3 O# y' T1 O6 ?! o6 U
hr = ptrConn.CreateInstance( __uuidof(Connection) );
8 T6 M9 S- I! L/ d* u# g6 ?+ o. g2 z/ b# z- V. ~% y
// 设定连接等待的最大秒数,默认是15秒
2 M! I, e l" x+ } ptrConn->ConnectionTimeout = 20/ K9 W8 S. L c
( s; F; m4 S" A# l6 v K // 打开连接
1 v& e! `& g/ t3 j- s3 M hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );, S2 I- O0 i+ @) S6 o1 Y
return hr;
5 a% G: s$ G0 w3 m }
% l, w( K) b$ D8 P catch( _com_error & pComError )6 l& Q" {5 A7 ~2 Q1 f I
{
2 d# Q4 u3 P4 d2 `& { …… // 错误处理7 k: Q' @" F) c( G
return E_UNEXPECTED;. f, Z5 v4 G7 E, P/ x0 x
}# v& u: r n1 K
}, D7 b9 x/ s9 w- r" p# m0 M: l
; N* p& i! U5 ]& N0 @ m4 q3 [; Y0 b: V* p D1 X' a
4.执行一个SQL 查询,得到数据集(recordset)
( p5 S: Q( W/ S- u* e9 f1 f' A! S7 O% H/ A% _8 f
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
3 i) B9 O+ T* P{
9 i: T3 |" Z! R; m* z) u4 n2 b Y: w try
7 s7 H7 r3 I+ H# M9 h" ^: d' w {; e) S/ v( e+ a; g6 g V
RecordsetPtr ptrRS; // recordset 对象4 G: m- T" D) g/ A7 U
$ E* t* _' W! p/ w0 D
// 创建recordset 对象实体
' e4 y( ?+ P' v+ c/ H, [ ptrRS.CreateInstance( __uuidof(Recordset) );8 e$ Y6 b+ r- R$ `" N1 Y
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, " P7 @9 H5 T; B6 D: e4 y5 K
adLockUnspecified, adCmdText );: u: Y, I* \- C, [3 @. S
% _5 h" j1 N* _. c. E
或者8 ] q# r/ S2 B% q: _3 F
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
) ^5 a& @' x6 C/ ]- D return ptrRS;+ N5 X5 ^) {5 W5 t$ q
}: a- u+ u% X9 a0 e3 ~7 M* b/ D# a3 N
catch( _com_error & a_pComError )
2 U% b; ~# C- O {
4 G; C( m1 l" a# Q9 ?! ^ ….// 错误处理
4 d# R N" I! r return NULL;
/ o9 J+ Z8 ^( Z, }2 D1 Z* s" k }; ^; D W' i; `+ B
}
& y+ t0 c- B6 z1 C+ R) S z- O7 M3 J& e: { J/ { s
F) {! b% X, }' l7 D% s5.通过数据集(recordset)得到列的名称2 x! I# g# K6 F
+ A% \. D; F0 V9 T! Z
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
' K; O: x6 q, @ char strColNames[][255],
& i6 l( t/ n& V" o0 l+ ]; l; f DataTypeEnum iColTypes[] )
- l8 U6 H7 w& y0 n8 V- a{. \4 k- D2 n4 p) E8 A6 X4 r' P! [1 l+ [
try/ {0 L$ [% `$ a- T& G- [
{ // 参数变量& e! h) b# y$ T7 A9 A( e; }4 S9 s
_variant_t l_vaIndex;8 S1 R# h, s7 b0 {" T$ ^5 Z& L
8 r9 O/ b1 g& W- ?) f7 Z6 i- l l_vaIndex.vt = VT_I2;; L2 y$ a. i' c g7 {
- M: k K) e+ A // COLUMNS总数6 l. B9 I$ } o) _
long lColCount;
+ F! k- v9 F1 x- U$ q0 p ^2 R" X4 a7 ~4 ^- t( v
lColCount = ptrRs ->Fields->Count;) W9 O4 a8 ~$ y' K
+ G- W8 \( m" V' x8 A* A) {
// 循环取得列的属性和名称% l+ U3 i. s; l; Q
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
& _* K ^8 ]" @7 z0 W {
# T+ S% r! X% b( a( z l_vaIndex.iVal = iIndex; // 设置循环索引
( D7 }" K* W# }7 Z6 d/ d8 x; U: R; j" |7 R
// 取得字段名称
0 e! l1 F5 n5 U2 ] `/ g sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);' U) ~# f7 ` Q2 j. G! W
% S! E- r4 M8 r: d1 N" g+ i: f // 取得字段属性
% C5 X; C1 a7 E/ _9 O/ u1 K iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;9 i$ ?! V; A }! T
}$ \. d% Y& l7 e+ I$ Q4 }8 ^
return S_OK;. A. [) Z1 ^& L( w8 g0 p2 b% C
}" j- I' C2 l, s- C( o5 ]% q8 s
catch( _com_error & a_pComError ), U9 ^0 j' a, k" R
{( Z8 b9 R# X0 _7 P
…. // 错误处理
) K' P. L1 f6 p$ I9 d return E_UNEXPECTED;+ W8 Y1 t. u' E8 K. I
}
+ Y) D& O n2 X/ _, s, f catch(...)! u2 L# W( w1 W2 K5 {7 S
{; E+ \& Y K3 [$ n& x
…. // 错误处理" x7 s$ p2 d) G. F1 }
return E_UNEXPECTED;
; a8 t/ D# E4 T; P: j; k1 E0 m }
% k9 E' ~1 C! o! e- n/ K}; F8 S# w! E v. C" {
/ P- w* A& o1 s! R0 L S2 v
6 I" d, \- ]& N& [
6.通过数据集(recordset)得到当前行记录
7 \# M- E( r# x
( i5 l6 V+ `& ]: w- P uHRESULT getOneRecord( _RecordsetPtr ptrRs,2 s$ l0 M9 `$ ?8 ] k; Z
const long lNoOfColumns,9 r- @# [4 z: A$ T
_variant_t varValue[] )
) m/ l* Y, u, A{2 q# y Z- n; \8 W* t! V/ r1 m6 m
try
9 s; F7 J8 I8 M5 e {
( w" g k/ J7 ~& r7 E // 参数变量- t3 ^# Y" g5 a0 w' X7 F+ Y1 I$ x
_variant_t l_vaIndex;
d7 G" \7 c- a3 X, n3 i$ h l_vaIndex.vt = VT_I2;1 \1 m8 W1 q9 l7 f0 r- H
) w2 v) Z8 A( `' A; u' g: p // 循环取得列的值) ]- Q& Q4 w# l2 P
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
. ?' E, x) v- R {
' `* J e( ]9 u l_vaIndex.iVal = lIndex;
2 ]- D; @5 K- B4 m4 c+ E7 p
" |. V+ O! h& J/ R q9 o: Q4 I' k // 取得字段值
% \; r. Z* h1 u$ P r! @1 \" z varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;( i; F% E5 f! y5 D2 W
}
% h+ \( w! U- X& U7 {, \ return S_OK;7 ]! y& T1 s' N8 X6 V( g
}$ g0 ?/ Y6 l% R+ g
catch( _com_error & a_pComError )
S! W& V) f1 L/ {" \2 ^: ` {
0 S+ Q' b( A( j3 q …. // 错误处理9 m A8 T/ G( o/ j( T# N
return E_UNEXPECTED;- g0 O0 x7 H: l; \ u( C3 T
}9 G r& W6 r' E5 X) g8 s/ [( y
catch(...)% T4 } W7 e" [
{
: [: x7 b* Z8 y( d- v …. // 错误处理
n5 o" n" E' w7 o0 @) M return E_UNEXPECTED;
- l% L* R' P h1 I }
9 v: C2 G* x0 ~# ^* r8 S) h}( o% N+ ?% |4 M' ~+ I
8 V4 ~- A2 g6 S- b r7 F e
4 ` U9 F6 U" p' T& I& O7.出错情况下错误信息的取得
- o) X3 c8 ?# g4 x5 q+ ~/ C4 d) y( r1 K5 c5 N& c
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
* V2 C; i" N* R; N% ^' U$ r T( C{
/ f/ |) a) |* ~6 t e) O* v; N // COM 错误取得! `7 O7 ~4 g# e
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常+ g* J' M* d0 _& D. s
char lpComErrorStr512];
) z! i# s+ R8 T
# c7 J& R; S: _+ o! H# | sprintf( lpComErrorStr512,
) `' c, f( \, n* O( X4 s; z "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",: y* B6 S/ _3 M( _
pComError.Error(), // 错误编号. v0 h; V2 `; U' ]
pComError.ErrorMessage(), // 错误信息
& B+ W' y. y! G( U (LPCSTR) pComError.Source(), // 错误源
{5 R, `5 e- g2 s6 j9 F' c: @# u5 e (LPCSTR) pComError.Description() ); // 错误描述9 z8 a$ {: p+ U
p' r& z$ l' C! ~. }) R+ U // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息' E0 c, A4 p; @! O
// ADO错误取得
& B$ ?. u$ h! O" k) _; v8 o5 d' `& q2 K# C% I" Z1 {: D! s
ErrorPtr pErr = NULL;
8 Y( E" l' {+ O2 L9 c/ N if( (ptrConn ->Errors->Count) > 0)
6 O3 s* `. ^1 d: r* t) k( g9 C9 l {
: Z% ]8 J. W) L3 w3 [; ], I" B long nCount = ptrConn ->Errors->Count;
: Q. r5 ?0 |% H& ]: s. W for( long i = 0; i < nCount; i++ )
; e) Y# n$ b) @; Y7 V {6 {. V+ ^" f) j& K. R
pErr = a_pConnPtr->Errors->GetItem(i);0 Z! n+ |1 w! k" s6 w' }' u# C
: [8 R5 h, {* d' V1 g- P
char l_pchErrorString[512];' c- v6 |7 f9 l0 S
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
+ h# E( l" K$ O: U6 @ pErr->Number, // 错误编号
' M; t* ^" l& N7 h( s# l& y pErr->Description ); // 错误描述( U2 | E) c; D; {% m' ]
}
9 u7 \5 F6 E' I }
! D" O) v" U u# h% i+ }' Q. A) H! J* _2 R/ X4 `+ a
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
# H0 T6 |$ E6 k2 G // connection 对象取得错误编号和错误信息。 |
|