|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。3 A: S+ S, c% C# ?5 m k
4 {4 ]; o8 a/ P# C
1、 用import导入ADO 的 COM 文件msado15.dll
) ?5 v2 I0 i3 b+ G |
& a8 M7 {& b" D: [6 a7 ?例如:
& ]) {% P0 A, h; R$ c9 F: Z7 B4 \* C) F, C; | N* I$ o! `
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\( z& C9 J) P8 Z
8 U6 A6 d9 R+ m T% w
no_namespace4 e O" K, [3 X: e2 t4 ]
5 ~: `2 {' \( K3 N, v# l1 d. E6 r* x) ~
" r/ ] ~5 U x9 w J# r5 r5 D2、COM 使用时初始化
. x7 t8 m: }- I6 [$ U1 D6 D# Q% ?3 W. O% {! R' F7 z. y6 ^2 R
HRESULT ComInit()
z' i- Z% `; m3 O# D7 `{ : N8 @; {/ {, x1 a4 h7 F
HRESULT hr = S_OK; // 默认返回值6 J) w9 ^( f8 f
if FAILED(CoInitialize(NULL)) // COM 初始化调用" S2 y8 z* c- d$ C$ y" e. ] r
{+ z- \9 [' ~; G
CoUninitialize();: g7 a5 a/ R7 }7 N6 e U
hr = E_UNEXPECTED;
; u( ~4 a+ g& E' l5 D% M" I3 A }2 \/ D, i5 b1 x: Q9 i
return hr;
, d4 w; T7 l$ C* a8 q' O}) a5 Y# i8 E" K- I( m2 P
) a* j, y$ j9 |4 v& G/ y: W% }! x5 |& N1 l, e8 A o0 m: |
3、建立数据库连接/ I$ L3 W2 Y0 X9 C3 l
. h0 v0 x# E" x5 E7 w7 p
HRESULT ConnectToDB( LPSTR pUserId , // 用户名
5 f; J; T: i1 }' {' W5 T LPSTR pConnString, // 连接字串
i) h8 u0 \3 |$ o7 z+ r LPSTR pUserPassword , // 用户密码8 [4 ^/ k9 x) Y L! N
ConnectOptionEnum ConnectOption ) // 连接参数
- ?3 L4 F/ G8 {4 b+ g0 _{
: I2 i* ~% e+ Z4 K: O1 a! ^" U/ T2 M8 T- k4 }
HRESULT hr = S_OK; // 默认返回值
& x1 C& j+ I3 v" y _ConnectionPtr ptrConn; // 定义Connection对象/ _- ^! B' F0 ^
# C5 P* i7 g1 b; ~ try+ k% L% }) L3 V, n4 ]
{% b8 }) E% z6 K, _ g( j
// 创建一个连接实体" R* q$ W* q- K4 D7 I! l
hr = ptrConn.CreateInstance( __uuidof(Connection) );
" ~: T6 {. t# g" J) g- c8 K1 H% T0 K' B) ~
// 设定连接等待的最大秒数,默认是15秒
3 j! d5 Q% G2 j } ptrConn->ConnectionTimeout = 20- C+ }" M5 J3 h7 [5 q2 F& Z$ O
! b B/ t* Y0 h% _ // 打开连接
1 @$ Q, D4 m# R% {, L hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
5 o* ~- F+ x, z" w D, I% ^' T, ^ return hr;
) H( i4 t' S S }9 c9 f, X3 Y9 f3 K
catch( _com_error & pComError )
' s7 H' x! L' Q k, I {
]% G. G8 N E# c' c, W! g …… // 错误处理# b$ |! g5 V$ K$ Q
return E_UNEXPECTED;. r- L4 `" D3 y" Z0 ]
}: G0 P" M9 |9 Z4 M
}/ V E2 `+ T G+ L
; U$ T9 [" M' X* G! Q, V' ]! V- o; x. s; ^0 D! K% v2 q; C
4.执行一个SQL 查询,得到数据集(recordset)
' R+ {3 l! F3 m8 r+ p) C* M
5 [( u7 w3 V) f+ d4 ?) t' n/ ~_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
( ~/ t8 E5 i* ]7 g{
0 e' m6 B P, b! w, W try2 y5 `. c# E, u, m( e; f
{, g, y" W6 s6 q+ O2 l
RecordsetPtr ptrRS; // recordset 对象8 i" _( C! \- Y3 A. Z3 h
6 x: V& N; h% K2 x% O _. C# v
// 创建recordset 对象实体
8 p2 \0 A/ X4 F& t# D+ ? ptrRS.CreateInstance( __uuidof(Recordset) );. e8 n# k n9 f) I1 F+ y
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
& i6 _& V" u( u; qadLockUnspecified, adCmdText );
M, j4 x' ]8 T/ H5 S: B' W
, F) c+ p7 [/ f: a' f 或者
, ~$ F% ], m i ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
, h, p \. G3 B, O# y return ptrRS;
8 h- W4 M8 }. P- Z( \$ |; ? }
2 {$ b/ j3 g* D% s& j6 W+ o3 ~ catch( _com_error & a_pComError )3 h, V* Z$ C+ v+ D: r
{$ t4 d' w U" x( u- U& S0 V
….// 错误处理
' c7 k* {$ r# x* q( E! R return NULL;, U# x3 m6 ]0 W* p9 q9 H* p
}
5 T- i' n5 k0 V6 N8 L* ~6 H}
, K) B) D6 }( K7 e C( z+ T+ ~& V& f) {$ u& \* g% y- J
/ A8 a( G/ }# D, I" E8 S5.通过数据集(recordset)得到列的名称4 {9 T' a/ H e) Q
! ]! [: B0 i( U
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
5 T" M. Y* O( }7 W3 T A% w char strColNames[][255],
# f* O4 u8 z, I4 R8 K DataTypeEnum iColTypes[] )
' P3 C* d* m0 e{& I& L! F, @3 V. g2 P
try5 c4 d- W: x% ?! l% R/ A+ G
{ // 参数变量& p! J5 g$ G' ?6 v- j
_variant_t l_vaIndex;
/ o7 Y3 _2 v9 s5 _* R5 f' [+ {
5 h: c; U0 X, c1 e# _! u l_vaIndex.vt = VT_I2;0 z3 i/ x+ v+ ~# }0 [
. b! @ ]$ l2 l' w. [; H8 G* P: @% d. p
// COLUMNS总数0 O% v( b( B' `( n M* x0 c2 _
long lColCount;
3 S) M) m4 E; B- \" h
; `' G, Q1 b( Y lColCount = ptrRs ->Fields->Count;
1 C# i* f( p' Q+ L, A; f4 l+ T
4 ?2 A2 n7 I8 @/ s, m6 u' g // 循环取得列的属性和名称& ] \: Q8 Y T8 N
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )9 a: W$ v; `0 p. _, X- j/ g. `
{5 T/ z- J B1 z+ F& v' [; S: L
l_vaIndex.iVal = iIndex; // 设置循环索引
9 h8 \! l) n% A
% _: y" h8 {, l/ J1 w A1 Y9 L // 取得字段名称
2 ^% E8 I0 S7 i$ t. d sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
- n( \( O5 f) w9 Y% c, H7 D% N$ r6 J; b8 r+ P
// 取得字段属性9 J+ s" z+ {" I7 q- n& p5 L$ }
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;) `4 n5 s& {, X# f S
}' M: N' F; `' z! O- e7 W
return S_OK;: d4 i* f1 G/ b+ b) Z7 q# w
}
3 u9 |+ G7 A6 E" K- Y5 ? catch( _com_error & a_pComError )
) M' N2 I2 x# p. D* @, H {
0 t: T% ~# F( g$ }6 N+ u5 ]' l; n …. // 错误处理% T- S. z* M; S; _! d" V
return E_UNEXPECTED;
4 G- J$ x0 A9 c/ \0 z9 {7 d# {% @' G }5 b$ M9 \# }2 C! H3 r+ | o
catch(...)( y: u U% [) |, p/ ^# i7 Q" P! Z
{
& ^8 z u2 B8 \2 ?" O …. // 错误处理- D5 g1 m, G1 Z
return E_UNEXPECTED;
( ^0 u3 X0 W9 A }" d8 O# l+ ~4 \8 I4 R' ?( V
}5 K2 D2 _9 r: N- a4 ~
7 r' r3 A- R7 s, R- |: L
8 a( n- n! `* v9 T5 C2 y9 G& u6.通过数据集(recordset)得到当前行记录 F3 E7 ]7 N* L9 T
9 z. t8 ^* I4 R5 [5 z' e" ?. iHRESULT getOneRecord( _RecordsetPtr ptrRs,3 e7 j' k7 Z' d
const long lNoOfColumns,
; l! d* C, K2 L6 p ~+ @0 \0 |) j0 k _variant_t varValue[] ); P6 m1 i! ^) y, t( Y: J
{
. o( o7 O" R( {$ ] try
/ h# ~! Q g, o7 j {
) @* v7 d; c% j" A8 @ // 参数变量
( g1 `2 p1 L9 L" M0 ~ _variant_t l_vaIndex;; y2 S% H( ]4 P* T) C6 q# C% z
l_vaIndex.vt = VT_I2;
# S6 a, c1 l l0 A# B8 q- M! {: b4 l% |. {2 R3 u
// 循环取得列的值
0 ]. q6 P; ~. J* c# X3 {) p' M for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )) F \- G8 |( } Q
{
2 ?1 O1 n$ u) o* Y$ `4 Q l_vaIndex.iVal = lIndex;
1 y- e& p9 P; \9 h( v( J" f! ~! a* a0 G: L) Y5 [
// 取得字段值: n# v0 d K6 L7 H9 G0 L3 G1 ]
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;+ v# P) d- G$ `0 X8 a
}4 S" k; K! I; q( u5 E4 O" s
return S_OK;
" J6 v: S4 D0 b6 c }& A( ~+ e1 [0 l o. z
catch( _com_error & a_pComError )
. v) G8 n& M5 C3 k! M9 i {9 Z+ d+ I) g& F: v- R
…. // 错误处理2 X7 Y$ A9 H0 q/ \, a
return E_UNEXPECTED;
7 t3 L5 ?$ O Z* U3 s }
6 A; N. Q- F0 r1 g( s% o3 c% C catch(...)5 z6 b& M/ L" f4 S" _
{
7 v3 ~3 R# X% E9 a …. // 错误处理9 D! Z( t1 k k; \3 }- x: [
return E_UNEXPECTED;1 |8 I7 I; s1 L- D& r+ k% j0 \8 p
}
8 B1 L0 q# M$ Z7 }}" {1 M5 B$ ]- N3 ]8 v3 j
! m j) ^+ H; @
$ H# {# j4 ]* A' ~1 L. A6 w4 M7.出错情况下错误信息的取得
0 B; ^9 X. \& ~/ {! C4 d5 Y+ {# x" B* @' d/ {; C0 R
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );3 h, @3 S1 H' h
{
) _; e* d- V" ^" a // COM 错误取得
# X% O" G- V: G' R // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常# f8 N4 Q8 B2 [5 K6 y& u& a& o# |
char lpComErrorStr512];( g2 ^ y" a2 V* Y9 a
& [/ `0 y+ u. Y* q8 H sprintf( lpComErrorStr512,
8 O i. q- a9 K "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",% `4 [4 ~; f) a+ D" k
pComError.Error(), // 错误编号
- l/ E" q3 i' O: `6 W3 e$ |7 z pComError.ErrorMessage(), // 错误信息 c+ }2 I' [2 O# ^, ~
(LPCSTR) pComError.Source(), // 错误源
@6 f; }7 Q" v( D, ?4 V2 h2 T (LPCSTR) pComError.Description() ); // 错误描述
: W# W; d! ]" E, T5 ~+ K/ ^4 \( D9 Z8 K5 L; a; d$ G
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息! D0 R* q- K8 S4 H: m# c5 g. Q8 }
// ADO错误取得' R: F# O7 G1 }2 E+ M \ g5 }
( C% k# @" { h5 b4 ]8 Q: e
ErrorPtr pErr = NULL;- w1 F6 o+ y+ B* s
if( (ptrConn ->Errors->Count) > 0)) p2 c. ?' o; U
{3 j" `- G3 E: M+ }7 W" {
long nCount = ptrConn ->Errors->Count;
) K( J- D2 u4 H( V, u for( long i = 0; i < nCount; i++ )
& m4 ^6 p5 M7 N* V# B4 S {
2 \# P3 h. x( m, M0 U0 L pErr = a_pConnPtr->Errors->GetItem(i);8 O. t6 \6 w( Y5 d5 [9 J. x
3 A; }9 a* r. z* ^ char l_pchErrorString[512];
# m0 ?- |+ V5 Y+ s' q9 b$ Q: x/ N6 m sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",8 N+ K4 |+ u& ]% X# M: j
pErr->Number, // 错误编号) h" `5 q. V' D, z/ z4 i
pErr->Description ); // 错误描述
. T0 M9 K( S+ p5 U }
9 ]8 c2 j/ x f }
' [9 v) ~: R' J! b4 J5 f5 L4 Q/ o% I2 t* I0 a
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问' F% K1 ^# n5 Y; M7 k3 q- U/ F* A
// connection 对象取得错误编号和错误信息。 |
|