|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。 k- s% y4 {# ]6 h, S% }
0 S4 Z" }$ I5 {5 s
1、 用import导入ADO 的 COM 文件msado15.dll& K0 E m; O5 T; W& @3 Y5 F
. u. S9 @& e4 m1 [4 P例如:
4 p: l# g# ]' ]. n; [: |
3 L: L* e7 `! W #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
$ t% S/ e {; j; S/ V- [: l
9 D# G2 r+ u/ ]5 G/ S) V: V( D no_namespace
m' h1 ?/ q. {' r. o0 z# {/ C( O O- Y7 F1 F/ p/ W- e. }
4 D9 t, G7 j, W) s8 c. e5 M
2、COM 使用时初始化 Z2 B, N6 f$ H+ _, l% n" k X) n
* w# Q2 w0 h' P: K+ v* G
HRESULT ComInit()8 [7 `4 X/ s6 D* k5 s
{ ; v. _5 n% t8 V3 Z7 x) ?2 O
HRESULT hr = S_OK; // 默认返回值
3 r7 @9 v& {' ?* f; Q" G: {4 o if FAILED(CoInitialize(NULL)) // COM 初始化调用: P9 ?0 p% w- g8 s4 H" t& N
{9 d8 c* l8 `* X8 B
CoUninitialize();
: B, Q' N" X4 @# z hr = E_UNEXPECTED;! z+ a2 B' B' x) I1 Q, E
}
, q( u+ y b$ J- V return hr;1 t8 V" {; }" c8 B, s
}
* [0 m3 Q" x3 p$ Q/ B' x- \# V7 s+ ^# c
" Q. b5 H! J+ T$ L6 ?+ U4 N
3、建立数据库连接) R+ j. u5 ]& a# r
- p9 I. E+ Y$ H, d8 ~% S
HRESULT ConnectToDB( LPSTR pUserId , // 用户名5 M- J* D- i/ a0 |6 z. M1 T- D
LPSTR pConnString, // 连接字串
! g t8 E' [, _) }% a `8 J6 R LPSTR pUserPassword , // 用户密码0 [1 M) N. q8 `/ v5 z
ConnectOptionEnum ConnectOption ) // 连接参数
4 n! C1 E: s; B2 ]" k{
+ p+ ~6 r5 O" z) U# {8 Y# _4 o( W4 E8 N! f7 g
HRESULT hr = S_OK; // 默认返回值 |3 U; U! w" n& r3 z$ ]
_ConnectionPtr ptrConn; // 定义Connection对象
+ c7 m5 W( K0 i) z: a& R
1 { e/ {; K# o( q. m& d try
- u' u' o& ~4 o q {, J6 w0 |! h8 r/ f: l2 r
// 创建一个连接实体
3 K* {) N7 }: P* t( X! c hr = ptrConn.CreateInstance( __uuidof(Connection) );
$ M- I4 w+ K7 r( l5 \
# A* Y: B6 P# C, u. U% W // 设定连接等待的最大秒数,默认是15秒! [$ r" S6 n, g' d
ptrConn->ConnectionTimeout = 206 B; ^4 G' t! Q% {. J; X$ J- A
3 q3 p1 l5 p8 u& ^* R. O# s2 z) T5 P
// 打开连接1 I' m; f8 }/ q/ y! v. h
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );9 p4 |9 D0 A& ]6 Y
return hr;
" q e5 [+ O# V6 B }
0 \8 P2 m, L& `0 N, D, G catch( _com_error & pComError )& X, j5 \( c& K0 c2 |5 K3 q
{9 G, J4 Z S7 c) c+ D
…… // 错误处理& ^8 n! d. Z/ N) T: w5 n% k
return E_UNEXPECTED;, H. z8 _1 d4 |$ Z
}; {6 ^% \) w' p
}+ ], A2 G- K! ^& w) E, n# q& b Z( B
4 e4 k* s8 B* s' [4 H @+ x
2 W& T3 C2 ]. A l# [
4.执行一个SQL 查询,得到数据集(recordset)
" E( Q6 B' W7 F- K3 ]- f3 P+ P
) V) b% i0 F" Q8 a_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
% ~$ t/ r/ m9 P, N7 }7 ]* Z{' m ~7 j. q U! @$ H
try
$ W! z6 Q0 y5 D& K9 d2 t* a {
" S" ?, i# e/ w0 L9 X RecordsetPtr ptrRS; // recordset 对象9 q: K% L$ c4 b: s( s$ {& Z3 [
* {8 _" T" L6 V. V
// 创建recordset 对象实体
! e$ w4 C+ @/ [7 N ptrRS.CreateInstance( __uuidof(Recordset) );# j$ L0 `& K2 U2 }8 i8 I
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, ; w0 i% M- T2 i7 n
adLockUnspecified, adCmdText );4 U9 I7 ^% `1 Z) |- c
' L( Q1 B) O/ Z+ v% h$ i8 V 或者% S1 }0 o! I M# X. q
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );3 X# c. R. M5 W
return ptrRS;
7 z) M6 h* n# N& t6 `6 ?; D% b }( L4 l, H- @ d" ~4 t
catch( _com_error & a_pComError )
4 B" c% q) g9 M {
0 C6 [* M: Z/ t( I ….// 错误处理
1 K: Y, c+ N5 y+ y5 H2 F+ F return NULL;
: X+ |# S9 o( b' E }: E/ @2 }. V, k. z- W. _4 O
}
( u+ r( f5 e# Y" A7 n
: ]$ s3 [0 _& s; ^. s8 r3 ?; E+ f9 {9 ^" `/ I2 d
5.通过数据集(recordset)得到列的名称, M% {) N- E3 ?9 U
+ w; R, B$ P2 w
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
% R3 x8 [, S( q1 D L5 T8 ]2 C char strColNames[][255],
6 W0 O/ K( Q$ i* O U, G DataTypeEnum iColTypes[] )2 c) X& x/ K$ [0 {) t( v% G5 ?
{
3 [( P# r* o* I2 W try! j1 T4 V$ ]5 n6 v
{ // 参数变量* W1 D- Q! M, W5 v1 H2 n8 _
_variant_t l_vaIndex;
# d3 u6 N$ P/ D5 n/ C+ d7 [
/ y; w; @1 \$ Z3 `9 J# @& m l_vaIndex.vt = VT_I2;1 \6 J1 t J$ e$ f' k: Q; f) o
9 H1 R# W5 {4 ?: f2 G // COLUMNS总数$ j6 F$ Z! w5 F' p& g3 B- n J
long lColCount;
6 {# I |5 ?' o3 N- n9 f1 k! D3 V. C6 v' E" Y- P) R5 a9 Y6 A
lColCount = ptrRs ->Fields->Count;
5 P" x" y6 _/ B0 Y1 ?! _: o$ \- S2 W& `8 V: {0 y$ W' ^
// 循环取得列的属性和名称" z3 o% @2 F. x: G
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )$ E, l8 N# D8 t Z) j! J+ J1 ?
{
& z4 s6 X W5 v" K l_vaIndex.iVal = iIndex; // 设置循环索引! t% z6 E# [& F2 G, f
5 `# G h- O: j
// 取得字段名称( j! I0 \( k s, D+ X
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
2 b% {% x8 z3 g+ e' a. b! }8 N1 l% m5 r8 [$ P- i1 _! {
// 取得字段属性# T L5 v+ S t- [' @
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;% Z$ s8 J! G% k9 |: @
}
- d- z3 a' U- G/ S return S_OK;% d+ B8 c# g$ N# {( ^; Q7 E
}
3 y( b4 s h1 O( \. S4 e, { catch( _com_error & a_pComError )% B& j# D* h T7 k0 ?8 @
{
7 Q5 k% D- \$ ?: { …. // 错误处理; R+ T. c& @" B
return E_UNEXPECTED;
& C# o- `% K f3 ] }
1 @1 ^6 M; P3 ~3 Q! @( a catch(...)( i9 _: @$ f! o( H% h, n
{% b# ?4 [6 L" \- Q! f" t3 i. V) r
…. // 错误处理+ i+ x" m1 y2 O& B: k
return E_UNEXPECTED;& T. }' A: E6 A- D5 c
}! p* x: V; ^& D2 i U
}! E. H- O/ \( d A) I
/ D' p* n; n$ v4 U* D% q! ^
) U; K |8 F+ k" ^( n6.通过数据集(recordset)得到当前行记录
5 D, p3 l9 \' c1 N
0 y8 [( V+ ?: W7 u' tHRESULT getOneRecord( _RecordsetPtr ptrRs,
, M. J7 t! ?+ {" c% [) p, e G- }2 y8 \ const long lNoOfColumns,# e3 l4 l4 S+ @# D, Q
_variant_t varValue[] )
4 Y1 g; g+ C0 N( ^6 ~. l{; @- s1 }% g5 j7 {8 D- W; \
try
8 Y4 `2 Y: U( F& B3 t# e# D9 K { q0 }- h, L/ A f3 ]0 H
// 参数变量) r. A/ ~0 _- x/ t
_variant_t l_vaIndex;
) G3 J# I0 D( G$ P) W/ r l_vaIndex.vt = VT_I2;/ C" L2 t; B" g- J) ?
+ p9 g* m6 M; C) p4 a( S // 循环取得列的值' P7 Y0 F; s5 n0 E4 h
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
* F/ U5 {4 |0 y3 G$ X {
; L8 m% k! ?* B$ Q l_vaIndex.iVal = lIndex;
) j* a% V8 f0 q, y/ c* ~' s3 F7 ~
! L; A% k. M8 S- e // 取得字段值
; U# W4 n6 X, t* M+ R5 Z% `7 T varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
8 v4 J/ E/ b/ E* q/ E }
5 G' c- d7 I3 K F return S_OK;
3 m, a2 o1 `* Z. e, L& W }
2 w) m7 _4 R) j! }% R- A3 y" a catch( _com_error & a_pComError )
- p1 c9 e( G) i; s t$ t- d {
" d |) W$ q! L4 S; H- t3 ` …. // 错误处理
u$ m' t& S, B* P4 ~% O) V return E_UNEXPECTED;# r& G: Y c2 c h& o3 o& _1 |
}3 @ a5 u& ?, k) B& I! j
catch(...)
. O$ R. |2 {- [: p/ y& \1 V( D {/ T2 l2 Z) p1 l! \. O* `
…. // 错误处理
5 }, ]1 C. h+ Q! G% |0 u } return E_UNEXPECTED;1 f: ~5 }0 ~ E7 s: v) J
}
; P+ M$ Z7 M6 O1 ?$ q- p}9 D7 j2 B" e" `* u$ w9 Q, R
: w, b7 \: a; x4 u ^ @
& _+ {" ]. n( X% @( l$ n9 X. f* l7.出错情况下错误信息的取得
7 A4 s) `* G3 b _5 `+ s# F! x+ s" c; ?& [8 t
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
2 ?* E/ P; H8 l{. [7 O- o0 t* W( d3 [
// COM 错误取得
& S" B$ ?' l x5 U4 U // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
" W3 J }* ?0 u/ Q( @# }" j- b char lpComErrorStr512];
7 e: G. @4 K0 j4 F: r0 T; J+ L/ t. a6 b5 Q# Z1 _
sprintf( lpComErrorStr512, }; a7 u8 \% J" w( r+ H0 i
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",
1 H" t0 x+ y# C( K9 {9 A# a1 w pComError.Error(), // 错误编号3 b4 Z" Y0 @, X w
pComError.ErrorMessage(), // 错误信息8 ~) F) z1 H3 s2 x+ I6 a) l
(LPCSTR) pComError.Source(), // 错误源) w- P3 Q( z* [. [: q
(LPCSTR) pComError.Description() ); // 错误描述* c( N( H W4 g6 g% k* H7 T5 b
) N" R7 U" \/ @/ U' e3 j // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息+ h& b5 n3 o7 B" V( g
// ADO错误取得
$ U1 }5 \# y( ~2 ^: O# D
4 Y) z$ q- V) f* j ErrorPtr pErr = NULL;
A( M, c E0 i4 d6 h if( (ptrConn ->Errors->Count) > 0); i9 q! s! r: B" m) S7 x0 P
{4 ~7 V$ F' o0 j) _
long nCount = ptrConn ->Errors->Count;
! A: I: K1 b2 o" B3 \. q9 z for( long i = 0; i < nCount; i++ )* U5 q1 c6 B, G, C$ ?% c
{
, L2 Y% o4 E* C: t pErr = a_pConnPtr->Errors->GetItem(i);" s9 Y0 \( o2 {! ]$ V$ O3 N
* p8 @' {7 Z, T4 H% ^3 w
char l_pchErrorString[512];6 U* E: P+ ^" C) ?8 `, ^; y# a6 V9 ?
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
& `5 O; M! | g" k1 S6 N! K c pErr->Number, // 错误编号
2 r) _6 s& k* z( \% B, `3 w7 b! q pErr->Description ); // 错误描述
' P+ \+ g+ _, J8 _6 m0 o: Q( q }
3 c3 o+ I6 C2 u8 Y3 o }
# c. {- A G3 @1 c) S/ T$ P" H: t) d, L* N) D2 o6 {! N3 d1 s0 f4 Y0 M
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
. Z7 _! s" d4 z) m1 Z& @8 N- [ // connection 对象取得错误编号和错误信息。 |
|