|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。* {: O/ o5 ?1 J
( E4 L. Y5 F7 c% T6 P
1、 用import导入ADO 的 COM 文件msado15.dll1 t' W( o7 n/ N' Z
+ B: Z+ v; j! P* D l例如:! n- v* I) A3 T
5 Q8 z- U1 `% c, E" e1 s' U6 w; U #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
" B8 B: x6 L, ~: P) E+ R! g9 {; `0 j
no_namespace
$ F$ ?$ n" ~, Y( ~6 T- g1 p
( M) p0 g0 X' l* B7 q5 ]2 S9 O0 _8 d' Z' n
Z$ E; w! F8 o+ b5 P2、COM 使用时初始化. \3 E8 S; U( A: _
" _" l# v% f/ P5 y( e/ T0 uHRESULT ComInit()8 X: f8 c& Z5 I# G
{
# I# t% n5 G0 q+ {* N1 i HRESULT hr = S_OK; // 默认返回值7 I$ s6 D6 B' K( D( m- L" m" t% s
if FAILED(CoInitialize(NULL)) // COM 初始化调用" g; H3 \* G) w7 ]6 {3 q
{
, R. _$ n6 M* b; h CoUninitialize();4 G' Q A+ X8 S: E
hr = E_UNEXPECTED;; n' d( b- k$ @
}* I, L' G0 C) r; f/ D0 O% J+ _
return hr;" K) }* @# d, \8 A
}
u V0 S( L8 B1 } Z
5 A6 j4 m8 C L! j: G$ S
; n0 }* C, K; s @% @3、建立数据库连接
1 j' F8 q7 U6 x x. u+ J1 Q5 `- G/ ~& I$ v4 S
HRESULT ConnectToDB( LPSTR pUserId , // 用户名
- H3 I! ?/ t) D: l! d1 G& e! k0 k LPSTR pConnString, // 连接字串
4 c$ J5 _5 a1 v! p* [2 o LPSTR pUserPassword , // 用户密码
/ m) I d# M: F! {, _ ConnectOptionEnum ConnectOption ) // 连接参数
/ K/ U( g7 R6 b/ ^- ~3 d{: K* _7 V9 L0 V- _1 P8 h
; \) t* O# w e; y HRESULT hr = S_OK; // 默认返回值
( L. Q+ n4 Y2 i2 b# o _ConnectionPtr ptrConn; // 定义Connection对象
) e9 K! I+ Z1 [2 S
2 G; t: \0 R: g* H2 ?) N try
" ?9 x2 E# w2 b4 v, a( { {
# m1 ~ B/ b, w$ k, A // 创建一个连接实体
! {" T9 g; s { hr = ptrConn.CreateInstance( __uuidof(Connection) );
) G+ Z3 `6 R- X, ] ^; l3 [% [9 p: S3 m* X' e: w
// 设定连接等待的最大秒数,默认是15秒
0 x: h" L i% f, ] ptrConn->ConnectionTimeout = 20! A; i; x/ m7 q2 `+ y8 _; l* e7 E
* g* Q3 N4 I/ x' q // 打开连接; y) D; x5 o/ H8 }
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );' e7 @1 A6 Q% p9 V
return hr;
6 p) Q& r' a/ ] }
3 P" F! w% N3 j) Z catch( _com_error & pComError )
4 B! P5 }9 C% _ {* d$ Z- W: I3 d9 t% Z5 L5 F
…… // 错误处理
/ ]) [- ~0 y; l4 v4 H" R2 E# z return E_UNEXPECTED;
q9 Q+ t* Y# `, o2 H: B. x) R }
6 w- Q& D$ e3 x( m6 q$ [}
, q& ]# I( b5 ?; ~
- E: C/ C$ S# D2 W5 b1 Y
& I& [- W5 J n, o, p+ N4.执行一个SQL 查询,得到数据集(recordset)8 y G+ B" [' ?4 N7 s8 M! j2 F5 Y
- }2 t: e* [5 y u4 U. `( z
_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )5 [! |0 C( S. q2 Q; j! ?9 T
{0 I4 ]1 V, Q" `& c* v d1 N
try" _1 z) ? R$ Y% ]
{
; M0 m- }: ^+ m. b RecordsetPtr ptrRS; // recordset 对象
7 S! M3 ?; r7 c5 K
7 U! l6 o" j+ _7 j- O6 T* h+ G // 创建recordset 对象实体
$ l% a- b5 p. w' [ ptrRS.CreateInstance( __uuidof(Recordset) );) K" l/ K. r) j9 b
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, 9 g6 O% H6 Q( I# i3 j
adLockUnspecified, adCmdText );
( L+ z; r N( w. ~7 n$ j" F& s) G0 s \- K, a0 i& c' l- W8 l
或者
: d. l# N3 G6 N. J4 t) b ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );: ^1 F8 `& V, i& d& C6 o% ?
return ptrRS;' Z# c( Z) [5 ^$ n$ ?9 {
}* I" Q z+ q# y6 N) q* P7 A
catch( _com_error & a_pComError )
9 a. P% C7 k/ v0 `7 C' | {
2 X6 o( y' L% B8 x! | ….// 错误处理) x R; R- Y0 C
return NULL;
V8 G9 G0 [! o9 G3 @ }1 \: v U) u9 M+ G, _; u
}
- \7 A1 }; \/ L3 s& [
% Q# f1 U- D2 C7 i, P, w
) V2 o. v& P4 s6 U3 w9 ^5.通过数据集(recordset)得到列的名称5 W( w) y0 k* q" t. M# _
+ T$ Y" d/ H! j3 U
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象' ?! y) @ j: h0 E7 \" V6 v% X
char strColNames[][255],
0 z' }+ V6 B* X$ s w DataTypeEnum iColTypes[] )
9 i4 X. z' `) e& Q{: _: d) j* n1 z+ J% ^
try8 z [; [( }2 w
{ // 参数变量, }8 U& C7 v2 H8 M% k# E
_variant_t l_vaIndex;2 `; M. Z; D( }4 ^- Y
& {3 G/ L6 e- L: o- m$ d3 u: o" N l_vaIndex.vt = VT_I2;) F+ y$ ?. Z9 g `6 I2 [
* g6 |8 k1 Z+ G3 M // COLUMNS总数
$ Y B4 u5 N4 Q6 d D long lColCount;
3 g4 M+ D9 v0 p6 b) h6 S8 a
8 S- k' R3 h y* n! F7 Y' ?8 l0 ~9 r lColCount = ptrRs ->Fields->Count;
$ ^0 t t' g) d
0 @4 L1 H+ G! _+ g. }: t // 循环取得列的属性和名称
0 W" F* E- f9 C# p; o) r for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
; `. r0 d5 E/ l8 a {
! E! X7 y7 X. X l_vaIndex.iVal = iIndex; // 设置循环索引, _3 \. V) e/ D, z, o
9 Q+ S" `0 I8 t2 M$ |& N8 R' V // 取得字段名称, _! K" K! V* X' m, I& b, K
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
- X6 ?; ?( N' i; k2 W& s6 w! B* B& \! a- T( ~0 }( N
// 取得字段属性
Q( s6 E% j, j3 v Q- H iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;$ V' x7 Z; a* R0 Y% R) }4 I2 }
}! O; u5 j9 I+ F9 z6 i
return S_OK;
7 U2 \: v! l0 z8 W4 U( g! J+ Q }
J$ L: W6 a" l# N0 ~* q# F% {$ J catch( _com_error & a_pComError )+ O* H3 U" J0 }( Z" k$ `1 y. g: g
{
: |% i- B% S- p) |4 P+ { …. // 错误处理% i% a P9 R2 k3 t* k" J
return E_UNEXPECTED;8 k `1 i3 o# q0 [0 {) ?- E
}& ], H+ ?! g! s, |8 s/ Y) p4 H
catch(...)1 F$ Q" M; G: k
{" w) G8 q: D+ h, `$ Q
…. // 错误处理
: ]3 Q$ U6 ]8 J, }+ N$ `9 m return E_UNEXPECTED;7 V) S' U0 O. I: p) T. s8 F
}
: D* P, E) k! y S' u+ {) H}
" Z# V U$ ?4 b! K6 }5 O, N( m, D1 X. q4 d
, r) D9 y+ Y$ E& R% E% c$ F6.通过数据集(recordset)得到当前行记录
, {, s6 R2 d. O. x5 ^ c- W6 y0 f6 i# T, U% W' D9 ]" V( {! i
HRESULT getOneRecord( _RecordsetPtr ptrRs,' e1 Q% X k' N0 D5 W
const long lNoOfColumns,$ i6 N6 _: t6 w7 \
_variant_t varValue[] )
1 @' U8 M" c5 i3 f1 W7 V. m{
( \$ C" f3 N! }7 U+ y try5 `) \. t. I/ @# g* r: t2 H
{
9 u1 f5 C7 M" C4 Z, G. k# D // 参数变量
0 s7 A) C e/ I1 P; c/ I _variant_t l_vaIndex;
) d0 }+ C" s& P; n7 V& d" g6 ?, n l_vaIndex.vt = VT_I2;- m9 m" Q% B% l* p3 R6 d
$ X: k, G' T1 u! l* H // 循环取得列的值
( R7 c4 d( i6 k) w. @% z- L* }) k for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )
( P) _7 K- D% b6 b { $ \9 K# f# Q- V( u# M% U
l_vaIndex.iVal = lIndex;
5 v9 a9 G* ?) V. s/ O& {3 K5 g
3 z* W4 ?5 B' Z // 取得字段值
. l# [; d# ~3 N$ W* a( d varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
% o# n- D4 m# o, k }; o; K9 q! e5 ^5 E( v
return S_OK;. N+ ]: K! o: F& K7 a4 L( T2 v
}
$ W1 O* T: S, a7 X1 B% v catch( _com_error & a_pComError )6 C4 p( }' A3 x8 X4 |
{; A( E. G% l+ U: z8 d+ ^; c
…. // 错误处理# J8 r) X) c6 Q1 Z
return E_UNEXPECTED;+ a& `6 i& W) l) V- ~
}7 E$ \3 ]2 u9 N7 w
catch(...)
1 M6 x! Y+ @+ y/ C, p+ w4 G {
+ v* s, K/ B5 E …. // 错误处理
: l- d& I& G# L return E_UNEXPECTED;6 n9 u8 u# y4 K7 a6 L4 ?1 G0 W9 C
}* p2 \$ t" Y; y% O
}9 p6 s9 M/ a, b$ U/ `3 [0 a- L! F# {) w8 k
' C1 C8 [0 m6 W+ l
; B2 V. l* I$ |7.出错情况下错误信息的取得* U$ l9 |3 T( k9 ~0 h
# y2 g% k) T$ E$ \7 J* j0 Wvoid ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
3 M: C8 X: V' v. _& p4 U{
. [$ X x$ T& D& c4 J // COM 错误取得4 t; @6 _- `2 E l% {
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
" n% r0 L F9 i; C& d; Y char lpComErrorStr512];$ ^6 J2 b7 v2 _4 U( r+ I7 r! ~
4 e4 q0 c A8 [% q( x3 [
sprintf( lpComErrorStr512,
7 R- @& K$ k# G "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ", w7 R% n; ]- J! H
pComError.Error(), // 错误编号
& Y( v# _; e6 m0 U" G pComError.ErrorMessage(), // 错误信息
5 n% n* D! k. D6 z (LPCSTR) pComError.Source(), // 错误源- J5 l2 E2 D" }. p$ W' A- e
(LPCSTR) pComError.Description() ); // 错误描述
! ^5 x+ l+ c( O( D% `, K c- N$ q
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
# W- C$ c) U0 D2 G4 r6 f9 A- m // ADO错误取得
" v' D6 b; _+ @ l) u* e/ O
K8 { Z/ q& l: E ErrorPtr pErr = NULL;7 V2 r% @" w' z# X7 ~# I
if( (ptrConn ->Errors->Count) > 0)# A# x8 u4 n" T0 \! G8 R6 V3 l
{
1 w! F+ ~; T6 o6 l% s long nCount = ptrConn ->Errors->Count;/ ?2 E4 Q( K, L3 [* Z
for( long i = 0; i < nCount; i++ )0 m2 g; G0 Z8 \
{; t' q0 K/ q6 f0 g# e0 A
pErr = a_pConnPtr->Errors->GetItem(i);
4 D% {8 [: m& `( c5 v8 M5 Z! Z8 D$ `
char l_pchErrorString[512];
7 G! s) {4 n6 R `+ q sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",2 L: n7 J ]: P
pErr->Number, // 错误编号& v; p% Z5 I) X* C1 K! z
pErr->Description ); // 错误描述
F/ P1 V% ^# }' s }
$ x3 X& b$ q1 [3 x9 J }
" r5 J9 z* j/ W, d5 M* @+ n; i+ [6 [) W; X* H4 A/ Y- D4 r
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问8 u# B2 z1 W1 |" j" Q$ K
// connection 对象取得错误编号和错误信息。 |
|