|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
/ X: R' n) f% T! o0 E* l
5 g, t0 k8 [$ X p3 Y3 m% s" _1、 用import导入ADO 的 COM 文件msado15.dll
$ z+ ~3 d" a5 P5 k2 t: u3 V7 d O* y4 K% T
例如:
4 c6 \2 n' w5 l# k$ _. J6 S5 g2 u; O& }! K. _) n7 n3 K2 h
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
2 H$ P6 A% \1 J6 U$ J" G" T" n
+ ~' O+ F, |$ F# Q5 `- j no_namespace& ^' d7 V" Q# v0 h# R# T5 k
# n& M/ n3 g+ u+ [# z7 |$ v
0 ^( S3 b7 M6 y- V) A
2、COM 使用时初始化6 ^, r0 I" O# j
n( \9 Z' C8 }
HRESULT ComInit()5 x) [3 z f1 h9 x Q0 v
{ 6 L# u. f% L0 a8 D7 L7 Q; ~
HRESULT hr = S_OK; // 默认返回值
9 ~4 _* ~$ c" E/ M; d2 y if FAILED(CoInitialize(NULL)) // COM 初始化调用0 C' G' W% H" U' F8 N8 |/ E
{$ S4 y4 L3 Q, G4 H5 l
CoUninitialize();% O) M) ]' r3 g" r
hr = E_UNEXPECTED;
5 C- y2 @" [3 p& O K/ O }1 D" y4 q6 ^/ ~5 ?
return hr;
$ N; T7 B3 @6 `+ V, w2 m% V: r}
1 c5 H0 G" M) ~! ?! _6 q& M+ k
3 G) r5 Y! U% n
) r& t! K) j3 V5 d9 R# L- W# o. s3、建立数据库连接
, ^9 g" D, f% Z' n1 z: r i6 a4 |% g! Q% E8 t! P5 u
HRESULT ConnectToDB( LPSTR pUserId , // 用户名
( o+ Y; L ?& P) X" D; a$ a LPSTR pConnString, // 连接字串 2 F1 M6 |3 K3 \& E+ o; f
LPSTR pUserPassword , // 用户密码
5 O& `4 U, b3 r5 _5 J ConnectOptionEnum ConnectOption ) // 连接参数* R# b. n3 l* {( `' w* Q8 B
{
0 C3 F" A! l$ ~
9 |8 G& x. Z5 U: J/ B HRESULT hr = S_OK; // 默认返回值
2 r* K$ G+ \3 G" E _ConnectionPtr ptrConn; // 定义Connection对象! P' Q' r0 I3 [% C
6 p( P" E4 ~. {( C5 x4 L: ^# d7 U try2 X5 B7 L' K5 f7 W0 j, B- q
{0 `% U# h8 r6 g% P
// 创建一个连接实体% K" Y( x' f- |( ^
hr = ptrConn.CreateInstance( __uuidof(Connection) );
+ j: d+ b8 x# d! L0 V* I4 y$ e2 d0 e' Q9 N
// 设定连接等待的最大秒数,默认是15秒8 M' ^8 | y4 S% k0 h4 u& ?" k
ptrConn->ConnectionTimeout = 20) X* L" u2 K/ B1 ]' J) T1 n
" n, z" a. H; \" P# D1 S. C' r // 打开连接
& w( ` ^* G- O hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
' K7 d: T8 k$ a8 q# @ return hr;/ Q3 B+ v ^. \5 d) r9 _4 k( c
} r& V1 W* \3 W' ^6 B
catch( _com_error & pComError ), C$ M8 L$ k0 Y0 r1 b5 \$ j3 }3 d
{
8 ~" l$ k0 j1 O7 }( `1 u …… // 错误处理
5 b2 I6 I. n9 F+ o- g return E_UNEXPECTED;2 F4 b! y+ Y6 J0 X# G7 s9 o) x
}
4 K: O% i* n- D6 y( K1 }3 G- ^}7 C! c7 k1 M) L$ K _* D3 {4 _0 `
0 l H4 A8 Z/ w- N S6 }9 h0 s
6 {6 H' G: a6 s# ~& W
4.执行一个SQL 查询,得到数据集(recordset)1 }9 W! [$ l* G, {
2 [# y3 Q! v) I9 B; C_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )1 W& t9 _6 _ o) G" ?
{% d5 x( y1 ], o+ v
try
7 z/ e+ _) R z& L {
3 Y! H- Y4 L* r' ]1 p7 I RecordsetPtr ptrRS; // recordset 对象
/ b$ |% G C7 L: H' C+ C- m( m: V
// 创建recordset 对象实体) J" g) u9 }. Y, i
ptrRS.CreateInstance( __uuidof(Recordset) );7 V' h) V, Y) @# C) c) \+ Y5 q
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
7 _# j: o) C* `& f9 k0 badLockUnspecified, adCmdText );$ r; o, A O; T$ L7 B W
* B( p {) `2 _ 或者7 q: A' v! Q3 |+ X
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
: v7 m) p2 H% b% g y& D return ptrRS;
* ^( `" e% w2 ] u7 Z3 ?( @! a/ Y }: Y* C; i5 ?( U, i1 w
catch( _com_error & a_pComError )5 U# ^$ d0 }0 M2 i. @
{1 [- |- D: H: e4 {7 C% L0 \1 r6 z
….// 错误处理
% k- `" b% g/ y! {, ^* Z5 F return NULL;# K) ^0 @( Y% |$ `. O
}" L( H4 y4 t) Q
}# l8 Q! K E n9 t! @) V$ t6 U/ d6 P1 H
& m; c3 V0 R' K0 D
* \3 C3 f8 i* J! P' S
5.通过数据集(recordset)得到列的名称
- f% f6 X9 ]" l- t4 \3 z* g" h T* N. j1 B1 W ?, y' {' p
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象, k: \4 D5 D4 {$ J
char strColNames[][255],, `- m& _* D3 I2 F i f
DataTypeEnum iColTypes[] )/ S% A# N! Y& Y' H$ ^9 ^
{; r' R% v3 a$ Z
try4 G. _9 f7 i2 E' l1 K& O
{ // 参数变量; N$ O. \ B: A
_variant_t l_vaIndex;
; c) H4 U, X# N* p3 D3 w( J2 g& z: l- [! t( R
l_vaIndex.vt = VT_I2;
% y$ G2 m: @) B2 U
/ c7 l0 r" V+ T `$ x // COLUMNS总数5 F& Q M- p5 z* D8 l: M
long lColCount;( A8 L' j- _! u6 k1 z4 W2 m; [! Y/ ^* v
6 j+ |; D1 V) M$ e- h
lColCount = ptrRs ->Fields->Count;
& \' G5 S2 C ]+ i% S' |# ?9 [9 Q @" \; Z4 }
// 循环取得列的属性和名称
- A' n# R! {- {, B3 E for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
\" k# c; I8 B3 T/ a4 A0 j5 P3 I {
8 L+ _" G+ w$ ~3 f8 ] l_vaIndex.iVal = iIndex; // 设置循环索引: U1 d$ q# F, ?! G; K
7 q ?# s+ Z2 [+ s- @9 @# H // 取得字段名称% X5 C% y: @# |" ]# {8 i; Z
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
5 ^: O/ o+ h# @4 E* S$ ^2 [' M9 Q; {8 Q3 l' d/ |
// 取得字段属性5 p) e' S& H' w2 p$ [9 B4 n
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;- F/ T# M r# e4 T4 S5 C
}9 T& b2 L( U3 A0 a! h) Q" P
return S_OK;. ^1 Q7 n8 J7 y' u
}
+ y4 e9 m) T: C# v6 x0 } catch( _com_error & a_pComError )
% I8 D& J+ L; {- V {5 ~" R U2 E! [( A
…. // 错误处理
4 i2 l7 S% N) F1 l/ w( b7 t: h7 u return E_UNEXPECTED;* {5 ]- f( ?9 H* {! R% \( a
}; k2 {9 q0 L. T* F, m
catch(...)
" Z- a6 x2 S; j, w {
9 M! {& v; G9 O& V- ?$ E1 k …. // 错误处理
- Q) X' T) M* l$ p9 g return E_UNEXPECTED;
" j( {: i' w) H" d8 u }1 C2 a! c6 C, R- n3 w: Y0 F! g
}& \- u9 ?7 ?1 [
3 _3 d6 ]0 A. n8 a
4 O# ~) G( ?1 ~- r& H$ R6.通过数据集(recordset)得到当前行记录
8 K5 }; C5 e- |8 Y9 q. H7 m3 I5 M7 x5 |5 o8 N! k) @
HRESULT getOneRecord( _RecordsetPtr ptrRs,
: R# H4 u# O* m4 |2 l# i7 l# a5 d const long lNoOfColumns,
_8 W1 w( P: K- Z _variant_t varValue[] )
, Z( o8 q {' w2 l# d{
: E' j F- B; q! v. ]# B; J, j S try. s, n, X& J$ D( c' n# g5 R
{8 W9 b0 Q' a# J9 A, ~, u# T
// 参数变量
# p& w, }! k8 h8 |3 l+ \ _variant_t l_vaIndex;7 P! d( o* b" y% o* m
l_vaIndex.vt = VT_I2;/ l5 m* v" U9 n- a6 `9 d
% Y0 u# \, }+ E8 G9 Q1 S2 j, x // 循环取得列的值2 ^6 a, M9 r3 R) e: { A' N( X
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )5 Z- ?1 x6 m9 z' O" \: G4 P
{
) R5 `6 P6 R0 S' K/ C l_vaIndex.iVal = lIndex;
& C, Y, ?# U; z1 p9 h9 E7 T4 W2 P! ~0 p# f+ R ~
// 取得字段值: J" f, P3 Y% h" T4 ^
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;' x( }- T7 N" e: a5 D
}
4 h x$ t% H7 W0 ^# f$ ]. K return S_OK;1 e. X! A2 |1 S
}% y" u2 F# y- H( j' [
catch( _com_error & a_pComError )4 G0 o- l# u6 {# a
{
* n& F, }3 [* \5 U9 C- x( l …. // 错误处理
0 A* @* N* G/ k0 I/ R- j% e return E_UNEXPECTED;0 l0 _: b' O) R2 o- V
}
, Y5 M( o, ?8 V. m5 J) n catch(...)
8 {$ \ [* a% _ {: x: u& p: y2 n( l% X. S; s
…. // 错误处理
& f& ?+ T" g' ^5 | return E_UNEXPECTED;
( d1 s1 o( \9 F* S& s }
# N! L9 w1 T% U; `! G. y4 H2 b}
5 n# e1 x5 X- I% B2 {$ J- C& e4 j& m( W9 D( J4 r0 N6 g3 q& F
) r, u+ o( A: B1 |% B1 ?$ p& l7.出错情况下错误信息的取得9 R! p0 \& y, Q, b k( W" T% s
M* Y8 X6 r {9 y0 ~
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
; u9 R' p j. H3 G{
% ?1 b: n) J! g& H( |( J* R4 H5 E8 g // COM 错误取得
: _: I- i. y+ z! B) @ // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
' A# E( |* B( Z' y( ?" ^, ] char lpComErrorStr512];. K7 y' v# L: K+ [$ m7 ]/ {7 Q
8 M8 b, P( V4 Z- R6 i
sprintf( lpComErrorStr512,6 H3 O$ p U) R6 V3 L, `/ r/ }6 G
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",0 |' f: W* I! O+ S; z; j
pComError.Error(), // 错误编号! F# n, F$ H$ d
pComError.ErrorMessage(), // 错误信息
. ~" u% P! w' V* w (LPCSTR) pComError.Source(), // 错误源
8 P! m9 T- I4 C6 S9 k/ C (LPCSTR) pComError.Description() ); // 错误描述
! C: z- k3 r' g; @, I
) W, p/ W4 R5 C7 Y8 }( k2 Z // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
5 t" i8 @: q" u5 d: U6 S // ADO错误取得
' j# v4 b/ L$ R) c
& [! \; E1 z0 D' S+ J# c! D+ b; ]2 D ErrorPtr pErr = NULL;
( W* z" G8 v; F9 Y7 _4 y if( (ptrConn ->Errors->Count) > 0)
1 {' g2 a' d) N. Z& P$ g {2 Q- A# n7 y3 R5 z1 c3 v
long nCount = ptrConn ->Errors->Count;& O' d" T* k7 G
for( long i = 0; i < nCount; i++ )1 P3 ~( O) m' E. B+ w7 P0 `5 E( `
{
+ d" z9 P% @4 x2 X7 n1 _ pErr = a_pConnPtr->Errors->GetItem(i);- Z; l% c4 } B- ?0 V4 a
8 P' M" t3 p1 o3 q' \; X' u. y, C7 h char l_pchErrorString[512];
# ~7 P+ L! n6 r sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",, _9 F2 l8 _2 {* F& |# H. c* S' w
pErr->Number, // 错误编号3 `8 z; T( h2 a2 g7 X! V
pErr->Description ); // 错误描述
3 O( x, t6 a7 {! ] }) S3 H9 E! d7 {# k6 |
}1 X0 g* @1 \3 |5 ]3 l/ n
6 V( H: k% o8 `, @) N // ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
0 T+ `+ L9 H, X. A' a# c g% Z // connection 对象取得错误编号和错误信息。 |
|