|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。
2 O$ y0 x. T" w0 p( y: M: c
( Y$ a" @; F- `1 t' d1、 用import导入ADO 的 COM 文件msado15.dll% X1 {: {! v! l; h' z
. k) ^2 T) h: j, }- K( Q# R例如:
; s7 ? i) k" ]$ m0 Y5 c8 a
. K3 o7 D5 o3 o R% K' H' T #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\
9 Y7 c3 d/ M( n
, x: d8 }: V( E, C1 ]1 t& M0 Y2 ] no_namespace" }! s; N0 u a4 C
Q9 y7 z H' N% D
7 W' M+ m1 U: S: @ P) n2、COM 使用时初始化1 j0 \ ^- [2 [1 l. }
, b: Y9 X/ w3 d" Q' cHRESULT ComInit()# R, W9 o' L9 i2 L s; U9 N
{
$ [" M4 @ F& l: S4 H: l: U HRESULT hr = S_OK; // 默认返回值
; l1 g: R0 ^1 R; w" i if FAILED(CoInitialize(NULL)) // COM 初始化调用- f$ M6 m1 Q) T/ Q+ M
{$ t0 o& T( o8 C% D; [# @
CoUninitialize();: |# J: X' V* W# V1 j) Q, j* X
hr = E_UNEXPECTED;- ]! F& Y6 I0 k+ y9 A+ @+ a
}
$ W N" x: j9 W0 \( X8 s return hr;
0 Z$ _* I: o2 N& ]9 U( C& p0 g}
$ l( ?% N( ~5 D( {; k: h
* ?5 E1 p& N. F# Y& c
# G! n! p5 m9 l3、建立数据库连接# V2 L v( f. i$ v: Q5 K. [ G5 F9 k
" u7 B1 B/ ?! ` [# kHRESULT ConnectToDB( LPSTR pUserId , // 用户名8 D; j2 a, m& Q! r/ G" V4 g% E
LPSTR pConnString, // 连接字串
: [) {- L6 a/ q$ E6 C. Z/ l LPSTR pUserPassword , // 用户密码9 |$ `' z; b% }/ x, B* n
ConnectOptionEnum ConnectOption ) // 连接参数
9 l' P3 H7 J& p% U{
$ N; K/ ~+ w# L* O% n! }9 }$ Q* m/ j5 i4 a
HRESULT hr = S_OK; // 默认返回值9 @$ ^# t1 S* L8 _
_ConnectionPtr ptrConn; // 定义Connection对象
: p4 F" a6 R4 B. E. {( {5 j. J
0 M0 w( E; B4 @7 Y6 N ~4 D try
$ N/ d5 ^; g4 R. A' w$ k, b$ n {- x) ~( Z, s# s! I/ _
// 创建一个连接实体
5 s& T$ q; [% a. u5 e hr = ptrConn.CreateInstance( __uuidof(Connection) );
6 L& z; S3 A6 u* G& Q% o! S
* Q6 y4 \, O0 J$ v2 R, `" Z // 设定连接等待的最大秒数,默认是15秒0 N1 K7 f. P2 ]
ptrConn->ConnectionTimeout = 203 Y1 g2 B! B) Y" w
' g0 X" \# ^, r) K- |3 a: d- p
// 打开连接- N2 b3 o# Q) y. a( j( E( H" P
hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );- Z7 k) Q; g7 q" N7 {
return hr;
9 d7 {6 d# A; p. x }
. |2 N1 {8 L9 c; x2 @ catch( _com_error & pComError )
4 g5 v, k6 h4 J; s* E0 Y {; E/ `: k% I" R) A7 h
…… // 错误处理. t: i0 K" X9 k' y' m9 I
return E_UNEXPECTED;" V- ]7 G, q' V X$ j
}
7 g: k/ b" N: r% G3 T}
7 G/ k) f& e7 Y8 D
6 j6 i. R% L; Y% i' N& c$ }2 P
. v! N5 U1 c# u' J0 A" ^0 n4 o4.执行一个SQL 查询,得到数据集(recordset); G/ P: w& d& T
2 Y6 X5 M9 b: Z. e! p2 q_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
, i1 m( F! {& W; w* T8 G{- i, b/ x# O# A+ |" t
try( i1 M) o- F9 k7 ?( j
{4 y6 Z! S% r# z$ M( \5 q* P6 \; _
RecordsetPtr ptrRS; // recordset 对象% j7 C1 k# Z5 v; n$ q- l+ W
/ l% A; l1 P* E1 A' e4 c // 创建recordset 对象实体
" ^: [' m' e0 G0 e8 U ptrRS.CreateInstance( __uuidof(Recordset) );
6 ?5 y) i& B: v7 }# u) t0 \ ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly,
/ @! Y- a7 N' m6 o6 P; U2 ^adLockUnspecified, adCmdText );1 p/ H+ ]% Z& w1 u+ D
6 H! e8 }6 V4 z( j9 J 或者% B+ c u+ D. b' K( U
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );- I3 l1 D& c; Z
return ptrRS;5 l8 c- ~! v l4 y" B- R. K# [ s5 H
}
7 ~* u5 z+ s, P) W c6 E! m catch( _com_error & a_pComError )3 N9 x- D5 {6 } D8 p
{0 k3 O& b, T3 h6 G3 p' a# t
….// 错误处理
. x9 T4 A3 ^1 y. h8 G2 y return NULL;" W- q* I) ~" e4 N( K9 \
}
: B9 f6 u8 d/ A9 [}. D( J; k7 v) p* a9 ]# d
7 B2 j( b# I7 U$ Z* T% P/ y8 O ^9 n) W1 W! b5 b
5.通过数据集(recordset)得到列的名称( r4 M, ]" Y' T' p2 N
4 C' @6 a( b3 K9 N: M1 |! UHRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象
1 L5 r6 l6 w" ?5 O" T& d( _# \* A char strColNames[][255],0 S# J/ R. [ g8 ]' a* Q
DataTypeEnum iColTypes[] ). F" A3 s M2 Y7 `9 b9 {
{0 |" G# y( |) H. ?3 S
try
8 ]3 R: G# `& t& W5 J { // 参数变量
6 ]- L* @/ w2 h" J! k _variant_t l_vaIndex;, H/ `3 g% e! }3 A5 ]* S, W0 z
/ ?: j% M% M; X! ]2 v
l_vaIndex.vt = VT_I2;
1 G4 v7 q) g) ]
+ Y; t- M$ M/ e' i9 J" d; e // COLUMNS总数
* J4 N, L$ b! ]0 U" `6 t long lColCount;
' y$ | d/ k6 v+ z/ d& ^
' P, x" ~5 S0 {0 D5 w& B& k/ C4 q lColCount = ptrRs ->Fields->Count;+ E! G4 {% S: \% ^
2 y( R- E3 _$ o' J! B9 s" {0 b
// 循环取得列的属性和名称$ J2 Y" x" n5 w/ v n( P' @9 Q
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )
# X" D" i# x: T! h* S1 M {
6 v; m9 h5 j4 H9 L l_vaIndex.iVal = iIndex; // 设置循环索引
3 w: }# H7 w$ }& X3 ~) M4 w3 n V- E; ]6 b
// 取得字段名称6 L6 A! v/ A/ L
sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
) ?5 |6 N* v) x8 Z! c& ~* f/ @
& _& }- X, A2 Q; a0 p( r1 E // 取得字段属性1 F# k/ F- ~2 U& s; w% T* G
iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;
; Q0 H8 U, Z/ N ]+ _2 w1 C }
6 z. F* v2 X, a6 P return S_OK;
0 m6 ~: r( A1 c& B" P }
! g! S- _6 B$ n' M# W d catch( _com_error & a_pComError )
( ?" J6 t* x* ]; f4 h4 W& J' z/ J) z {7 W8 X: D; _2 E g8 Y8 _# z( m& t
…. // 错误处理
% d3 x' y# Q4 { b! V) h/ U return E_UNEXPECTED;8 { l: U5 P' v# L/ o- N
}
, I U0 ?. x6 _) u catch(...)
4 I5 ?$ ^1 T! ^) J7 ?8 W' t {
! z' M: `; O1 I! u, J …. // 错误处理
4 ^6 b6 h7 E% m4 A" g F" c* g return E_UNEXPECTED;
+ A3 c0 Q# E! A% ~9 f! D$ j" ? }
& U; p) @' {" W; P2 H1 `' I}
5 b. t5 E( Z4 ?1 l* j0 P
( e9 x. Y+ P9 W; E6 v
2 k5 t# L4 @8 U8 P6.通过数据集(recordset)得到当前行记录& d# ?; X4 M9 E2 Y$ h
! f5 g# h# Q7 T. t% t- ZHRESULT getOneRecord( _RecordsetPtr ptrRs,9 G- H( `: U* A
const long lNoOfColumns,, i7 |1 M& F Q H
_variant_t varValue[] )
7 [$ Y I2 J5 }; d# k$ ^! ?+ s* `, Y{
7 `; A5 |1 Q- Q6 y* i try
# j( o- n9 Y) s {2 D3 d( z; G; H( e i% t0 U, N) ~
// 参数变量
& S$ L) t# a: o( p+ ?4 I! K _variant_t l_vaIndex;; E; l9 f( a5 G9 t$ {0 R. k
l_vaIndex.vt = VT_I2;5 u ?( w* u8 X2 f( R3 b
7 N. F1 R& i1 T
// 循环取得列的值( j; J# o( F4 @0 ^% b( M0 J
for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )5 G3 ^0 Y/ f* y5 l( o9 Y
{ " P/ X, G o6 i- I& a
l_vaIndex.iVal = lIndex;4 T7 a8 a0 r! {' L& Y
! r1 e5 T% q& j3 d // 取得字段值6 g# O. ^2 {0 E ]/ k8 h G
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;
2 S# j& s7 C) E6 g }& Z8 L( M% Q0 y/ C. \9 ?& \- T
return S_OK;9 d4 |6 {! ^9 _
}
1 W; C: a0 D% U" Z0 [* V) L catch( _com_error & a_pComError )
0 f2 L- ~* ^$ K% H2 J6 S {
' c& @0 _8 a! J" Z …. // 错误处理 M. g$ {: b5 h9 w( B: G6 E
return E_UNEXPECTED;
; l( B" o6 i4 N }* j3 g7 w# a( s0 j) x7 |3 g
catch(...)
4 w- \5 D0 C; W7 X; P3 E {# S/ ~# k9 v# u+ z
…. // 错误处理' B0 o# [3 }9 z$ Q1 P
return E_UNEXPECTED;, R3 e0 v2 i+ ]; q+ r5 ~
}5 L$ j) J6 ^! E- ^) ~/ m/ L; |
}
! w, Y) w; |8 z& ^7 L
: N! }/ M3 G) X$ G2 J8 c8 O' I: ?, W o
7.出错情况下错误信息的取得& p7 x! e" \; O1 J
" O: w( F- b2 Rvoid ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
9 y0 o9 |- Z! w{
' P4 L' \$ @% f; e- u! r // COM 错误取得
: t0 k& f. d. J e8 B // 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常" Z1 a6 n" p- T4 G
char lpComErrorStr512];; L* U" K9 l* \! N3 T( B
6 v! g5 _# \& ~ sprintf( lpComErrorStr512,
! i- y8 V7 E% F% Q+ N/ B l4 G" m "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",
% J7 R# p& B2 O ~' s8 V4 E5 R pComError.Error(), // 错误编号+ E: M' S6 i3 p7 ?! p
pComError.ErrorMessage(), // 错误信息
9 [/ T6 j6 S8 Z+ O. K7 R (LPCSTR) pComError.Source(), // 错误源
* K" ~8 [6 p3 U/ \ (LPCSTR) pComError.Description() ); // 错误描述
; p2 J& l8 ?1 T9 Q0 D- n6 ? ^3 P& l4 L7 G# a- d
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息3 w, }; v1 g/ S+ P( \
// ADO错误取得
4 M7 r, _, U H: h! F% y& ~7 k4 f' |! h A0 D. f( k
ErrorPtr pErr = NULL;
: X5 X9 o( X+ s3 c. ~/ } if( (ptrConn ->Errors->Count) > 0)
/ R; c. \! | r! q! S# f c* C$ ?$ E {, F/ }6 }5 s) [' \! x) h
long nCount = ptrConn ->Errors->Count;2 k g; |; ~0 Z; K. x. b# _5 R( l
for( long i = 0; i < nCount; i++ ). X: g! q" E, t% a% h! e
{# _+ m! d, F% j$ }% x0 E
pErr = a_pConnPtr->Errors->GetItem(i);1 I" x* o' k8 y
/ e2 c8 }# i, C
char l_pchErrorString[512];
4 t- R0 F W( G8 a( {; F. n sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",
1 ^7 ~) z8 d$ V) w/ r pErr->Number, // 错误编号
) ]$ Y% ?2 q5 e0 Z pErr->Description ); // 错误描述8 H8 L$ C8 N" v7 X# I: F' q5 ~
}
7 l' j n6 _ L% ]5 p; P }
" P5 m m8 {5 I; |- R) ], O8 L1 _5 W. [' }3 e2 w1 d
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问
1 k. T+ v1 ~3 {6 C8 e7 V) a // connection 对象取得错误编号和错误信息。 |
|