|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。* R3 m; [3 |5 b9 o
/ V$ @. M( ?. J# m Y/ K& G) T1、 用import导入ADO 的 COM 文件msado15.dll
6 H. p% v7 u$ K) q5 L
) J2 F# K! D+ L0 i" ]; K例如:5 I ^5 c0 y& v3 `/ X
2 t. q1 W$ s; [ d8 c4 ^6 n z2 C
#import "C:\Program Files\Common Files\System\ADO\msado15.dll"\1 s! f+ F4 R0 F0 t
# J1 n" h G( b4 t- I) z no_namespace
. g2 U- ~7 G1 n- p; ?! Z* T" {0 R2 X9 B& i. r/ F" [
5 ~+ ~( f U% `! f: Y& V# o
2、COM 使用时初始化
2 f) ]. b/ o5 i6 F
; M4 h( z4 s7 THRESULT ComInit()7 |1 u* K1 W5 l
{ ! u, n8 l8 i; W: \ q" h
HRESULT hr = S_OK; // 默认返回值
' z- s" T, d% L1 v: e if FAILED(CoInitialize(NULL)) // COM 初始化调用6 H, S1 G2 A/ M3 i4 R/ S+ n( [
{% b- N5 }/ |/ j8 Z- B2 u; x2 `
CoUninitialize();
5 k% p$ [; k" h* m" @ hr = E_UNEXPECTED;
; X* s# Z; g8 ] }
: ~: E( F# a2 d return hr;8 A. p# Q- U6 _3 l; O1 H' v# D% |
}
) {" V6 E* T5 Q* r# \5 [, Q. t: a3 W* i# e2 B6 x
/ J* ?1 ~$ t. y4 F: C8 ~- u3、建立数据库连接
8 D- s( p1 j, [+ e ]& D. V
% i# X* h. ^ f( Z1 T) E0 p* s0 NHRESULT ConnectToDB( LPSTR pUserId , // 用户名2 Y: S' e Q1 j5 i9 T# o1 n2 P; l
LPSTR pConnString, // 连接字串
$ s% D+ b) \8 p! M8 \* w LPSTR pUserPassword , // 用户密码) b' S& G" q" j1 M% Y' I" n
ConnectOptionEnum ConnectOption ) // 连接参数0 i; M! H5 }- [/ _, P
{
- }1 U) \6 q1 }- }/ x; A* ~8 K) o/ `4 k
HRESULT hr = S_OK; // 默认返回值
' ] @2 |& I' s9 r- M- V# t _ConnectionPtr ptrConn; // 定义Connection对象
* O9 T7 D1 Z, ^$ w8 E: O
# j$ I# ?* E* q8 O P+ r6 m try
' C. K. O) u* e: O$ y h4 m' o {+ T3 p# l6 I3 ], o w
// 创建一个连接实体4 \* _/ P2 z/ ^8 P8 B" R- [
hr = ptrConn.CreateInstance( __uuidof(Connection) );
/ R8 b2 ~9 ^5 F' R1 Z3 v. x& n1 g) R9 G3 Z
// 设定连接等待的最大秒数,默认是15秒
; U) k; X3 P+ |+ `& A+ O! e ptrConn->ConnectionTimeout = 20
8 X" G% B! {6 C d9 ]* c5 S) V7 b! Q4 R& T# h% d
// 打开连接+ n5 d' @# h+ k2 k
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
- Z4 O5 H% E9 a5 d9 n' _7 r return hr;) b3 O5 G2 n z3 e. }! S) @! f5 F" v
}
S/ `* V9 I5 t" T* M. ~ E catch( _com_error & pComError )" q5 ~, n4 ]9 I8 F! q
{! H) Y$ N) i* v
…… // 错误处理" T% ~; s7 R' `7 f
return E_UNEXPECTED;) O: v7 ]/ w" z. O6 K, e) Z `
}+ U. l! J% {% K8 p2 z) y0 |; v
}
8 C, [ F5 j) L1 a% i6 ]5 C% l# I8 O" W- g! d
) I$ b$ ^, u1 m8 O4 ^: m% A1 a9 ^4.执行一个SQL 查询,得到数据集(recordset): m9 z- |6 R. `5 n J/ F
# n1 C3 s) u3 t# D_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
1 ^7 S" B( u6 R4 h{4 U o; B' A: }, Z3 [
try
& Q8 z. I2 Y: Y {& m) l0 y0 d5 p
RecordsetPtr ptrRS; // recordset 对象/ v1 b, P3 M9 I `
5 ^- W; Y; H8 p3 u' I1 C
// 创建recordset 对象实体3 j5 l3 K- D, h
ptrRS.CreateInstance( __uuidof(Recordset) );
) u; n/ }* z4 Q; V, i$ [) {6 r C ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
( t8 f' d3 Y2 W2 G- Y) }adLockUnspecified, adCmdText );
7 A0 B7 v; e+ u7 Z% x: G0 E( W2 b9 P0 R8 [8 y. I4 m3 E7 `5 ~) E
或者
% L: Y# V4 ~! N ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );6 L- a* P! @8 u$ V, _2 ^
return ptrRS;
7 ^4 f0 E; A0 O! f# F' R }9 b& S3 Y' \$ e# ]
catch( _com_error & a_pComError )
: \' M. N9 S/ X( Q6 C {+ x2 ~/ ^4 }! D; h4 F; J: \6 g
….// 错误处理. L) g9 X W) l/ W
return NULL;3 S% g P5 T3 @& C) L
}
' U2 c% m9 T( x9 K0 W}0 ~3 v: @+ w% b$ D7 s6 `0 ^
7 ]- ^- [* k6 W* T3 ^1 a' z/ v/ [
" O7 O: ]- v6 e
5.通过数据集(recordset)得到列的名称# G& ~. o3 U" ?
2 M0 i4 {6 ]8 g6 l) o1 N
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象: y' r0 f! E& [; d
char strColNames[][255],
/ W4 O7 Z7 F4 F4 v DataTypeEnum iColTypes[] )
3 h$ n4 q- `& y5 w* {, r{* j6 v! Y5 E- s: A$ Y
try
, k5 C8 b8 q: w { // 参数变量
3 ]$ M* R4 K: M B+ j _variant_t l_vaIndex;+ o8 M/ \) k. s
0 B9 X1 V+ U- C5 p0 U l_vaIndex.vt = VT_I2;6 z) A+ X7 S8 H' P8 e* z
5 n: D9 n% @0 c# I+ \8 k // COLUMNS总数
: P7 {( h" N% R long lColCount;# \, h# z8 {' G& |
! i$ e9 U( @( ]. G; y0 z
lColCount = ptrRs ->Fields->Count;
- z& h# e% }( F: c$ ?9 p
8 ~5 h; T0 w9 X) h* i // 循环取得列的属性和名称7 G. j! v$ T, P9 t& X% C# u. i
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ ); `# R8 {2 I5 c1 ^5 U$ P y6 |1 a1 T6 @
{
# K' E* c2 f4 K9 `; r l_vaIndex.iVal = iIndex; // 设置循环索引
6 j6 \& I3 v7 \( ^, y: X6 \' L# A9 Z7 |8 G/ z1 p
// 取得字段名称( I6 ]+ m( Z9 N t6 C2 t) H: |
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);( @! Z# p8 ~, Q) u. U+ o+ s) M( r: @
5 {2 R8 j" Y. y0 d- r) _
// 取得字段属性% l9 ~( J( W: f. ]- i7 R: p0 ^5 Z
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
8 {& |7 O/ O1 p0 u ?: m }
) K6 D5 P# q; u# O6 ^- b return S_OK;
& ~5 R6 \6 D; [' K4 e# l }
3 t' ~( P9 t% l6 D catch( _com_error & a_pComError )
7 t( f2 Z6 P! q$ F: U( V1 l0 ]5 T* s6 F {
" W, x; N; \0 S3 |. k …. // 错误处理* ~! L7 ~2 R: C6 }2 g- c: ~" S5 ]5 @
return E_UNEXPECTED;
# K0 `/ [# k1 _8 a7 R8 H9 F }! B9 J% \9 T) z2 K7 C$ I' w
catch(...)
3 t4 s! _, K0 w+ A5 O3 c2 [ {
5 @0 W3 ?/ _: i2 w …. // 错误处理' k" W" V4 ]- }5 N0 _& W
return E_UNEXPECTED;
/ E- x* }; N z1 S8 V4 m4 U9 v }
% g( n: d+ c1 i( z}+ O0 o. `$ _) ~; }3 f
4 p. O% @8 }1 R5 N+ w4 H; ]3 o g% M7 n$ n# c- H) N9 |* x0 x4 Z
6.通过数据集(recordset)得到当前行记录' y" K! _7 U+ [
+ Q9 v2 s/ C+ THRESULT getOneRecord( _RecordsetPtr ptrRs,1 z! N. v2 Q$ o( r
const long lNoOfColumns,
$ m8 T: d. }% T. K _variant_t varValue[] )
- v( k) h! F0 l; {{
. [; Y* _# D% r4 _8 e7 w1 V try
" R& \% C2 l. y2 [4 O( s {
! Y, K4 c5 L9 M/ O ` // 参数变量' i3 M6 @7 z* P* O2 R( e
_variant_t l_vaIndex;
- w! n# w* C5 @ l; {/ b k, p l_vaIndex.vt = VT_I2;) ^2 T2 E, d7 R/ ~* S: l( ^% }6 m
f5 e9 q5 e; P. B // 循环取得列的值
0 X) ?- F# n' R8 y$ w1 Q$ Z for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )) p' {' h+ E- S
{ * x& G4 | X8 n
l_vaIndex.iVal = lIndex;" z3 Y# f, }! F+ G
( q, I! D* ?( m& w6 y1 |
// 取得字段值
4 Q( i& Y+ N- P2 Y8 p varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;& Q `/ L0 y1 `* M/ R0 ~( H! [* ^
}
; t8 O& o- s1 W. [! x return S_OK;' t" b8 ]3 @ K7 h2 `2 O
}
* p9 H1 g4 r( [1 ?% i catch( _com_error & a_pComError )8 d$ k3 E5 h3 _7 s# H9 ~
{2 ^; A+ W+ ]/ }! F, }2 z
…. // 错误处理
$ s, Q( O# K+ v/ |, \' F0 H8 v7 l$ X return E_UNEXPECTED;1 }7 {# G) V/ j u) N n5 B% i9 d
}" ?/ m% M, D* @3 s
catch(...)8 ^" ?, f, a( {
{
/ x0 Y* G3 u- G …. // 错误处理, i1 w, N6 ~ G( U
return E_UNEXPECTED;8 B) o* F- o- K
}$ Z, E7 P, ^. X/ i8 l
}4 W- D, S- t; L1 Y; F
! g# B/ e- `" D# y
3 N$ j+ X4 J9 U/ J7.出错情况下错误信息的取得: C6 K9 V. C( G* b& `
/ W* E c$ g9 p" r9 K
void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
7 d) N: [1 i6 Y8 s{
$ u: J# c9 d# O% @8 V! ^0 @! y0 o' e // COM 错误取得% w' I2 H) \2 j
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
' E5 b( O" l7 u: A char lpComErrorStr512];
( R5 x8 o! O7 H* [& V% Z1 v/ e7 M& O
% C0 S$ p- ]$ d2 l- z- } sprintf( lpComErrorStr512,& q* }* X$ F9 t1 D
"ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",
. U- E$ ^% v" c pComError.Error(), // 错误编号( j% c- M+ B7 b# r
pComError.ErrorMessage(), // 错误信息
0 f: b, G1 w7 S) K! j% J, \( l (LPCSTR) pComError.Source(), // 错误源" ]7 I$ v1 o( j1 v0 Z7 y2 b1 f
(LPCSTR) pComError.Description() ); // 错误描述
7 k$ ^! m' X, s5 C4 A
* D6 X$ _0 e/ c/ d' s1 z7 m // 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息( u3 L3 {8 Q4 X( m2 y
// ADO错误取得& V @ [' x: ~, ]) D' H
$ b) m8 [/ \2 i! Z! L& a ErrorPtr pErr = NULL;, R% |9 q6 R! N
if( (ptrConn ->Errors->Count) > 0)7 R/ Y, K2 G+ n* e
{
* Y- f. a5 X. @" U9 Y long nCount = ptrConn ->Errors->Count;
7 W( w+ R" X- @. e( v+ U for( long i = 0; i < nCount; i++ )3 S2 R8 ~: \, b; \; h2 X( l
{
1 r( s5 f1 i& w8 Z5 Y& E5 L- C pErr = a_pConnPtr->Errors->GetItem(i);8 N4 r) J7 ~8 Q
# C$ d% n" i2 L: g( [ char l_pchErrorString[512];
' E) I# L1 s$ V) b# l0 ^ sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",/ [' M! k V8 d
pErr->Number, // 错误编号
% y6 P' a* a2 C- W5 z6 u6 s pErr->Description ); // 错误描述
' C3 T9 ]! l. x8 L& a3 Q }
" M. T, Z9 o, Q1 s. C4 D3 q! \ }
6 C9 V- [; x" _/ S4 f. m" k. f4 L8 S$ S* R& Z* `" M) s' Z9 D
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问0 z& H9 |( t3 r0 n2 d
// connection 对象取得错误编号和错误信息。 |
|