|
|
对于在WINDOWS上编写数据库程序的程序员来说,ActiveX Data Objects (ADO) 是最常使用的技术了,通过ADO可以简单的实现数据库的连接以及数据访问。但是在VC++中使用ADO时,却因为是使用COM的方式来调用,常常出现一些系统无法编译通过,或使用中程序非法出错的问题,在这里想大概介绍一下VC++中调用ADO的常用方法。. B$ [- Z' I' O/ S) f
. t4 x# k5 Q2 M) j" G
1、 用import导入ADO 的 COM 文件msado15.dll
3 [ q5 M* K. ?1 V) T) D0 J$ v5 E$ Q) L( d; g
例如:
' W7 O" a# H I
8 y. {9 a$ H4 }7 p5 A. X) \ #import "C:\Program Files\Common Files\System\ADO\msado15.dll"\6 K1 Y. L/ |4 s( `
6 i: h5 J/ M7 K6 w# n
no_namespace
( o2 j3 q$ ^" I/ D9 G- A1 w
9 [, ]9 \' ?9 G4 G z' c! b1 ?# k) S: Q- q
2、COM 使用时初始化" Y r( G }, I3 ^" B3 b' P% I
# a2 \3 N2 ?1 H+ u9 d! n8 |' M4 jHRESULT ComInit()' Z- O( e4 E7 F
{
7 ~2 B+ m+ J8 a+ v HRESULT hr = S_OK; // 默认返回值
, ?1 R& i$ G a' a3 R! _ if FAILED(CoInitialize(NULL)) // COM 初始化调用
h' I0 V9 R1 H% K: y {4 h. ~ Q$ s3 w
CoUninitialize();
r( Q' e; V) T! o hr = E_UNEXPECTED;+ k1 A3 l _/ e+ q5 T
}" c4 r& Z( _5 R
return hr;; S# T5 H" L5 v+ {* n$ X6 r, x
}, _$ Q) x& s! }; V9 h
* o- _. w7 e, a, D; ?7 n
& Y& R$ Y8 Q" U9 i* t3、建立数据库连接' O& l$ o+ W. m
" W/ n$ {7 ~7 Y' S- C& k: _
HRESULT ConnectToDB( LPSTR pUserId , // 用户名% J$ Z, v' m$ s& W# f# H9 N- o
LPSTR pConnString, // 连接字串
& z% o2 m* T3 Y) Z) f. ?' ^ LPSTR pUserPassword , // 用户密码$ i5 Y7 F- K) m6 P3 j
ConnectOptionEnum ConnectOption ) // 连接参数) b' a, w+ `9 L. y0 n
{
9 K# b. F! `( y0 b' _7 F7 M. @4 {& `
HRESULT hr = S_OK; // 默认返回值8 O/ X- U$ U% t/ M4 }3 O5 E( [
_ConnectionPtr ptrConn; // 定义Connection对象( W+ Y% P4 h0 q6 B
0 c' d5 |, F6 D/ e# Y* |; V
try
1 K# [/ u! x6 \/ l; D( f {
; O- u( U- w& Y4 f1 Y8 ^ // 创建一个连接实体
4 q+ s+ c8 f' E hr = ptrConn.CreateInstance( __uuidof(Connection) );/ ~4 }) i. f& o' s( [! g' Z O
' m2 k n& m/ T1 m7 g
// 设定连接等待的最大秒数,默认是15秒- e& L. q: X; z! Q
ptrConn->ConnectionTimeout = 20- A( l1 l+ }3 Z: X7 D, F/ n+ o, U
, J |5 f) O4 u/ {, n // 打开连接
& D4 L! c% t: N. R6 E8 ?, g2 ^ hr = ptrConn->Open( pConnString, pUserId, pUserPassword, ConnectOption );
1 V" e- |# [6 M return hr;
0 ^. h! W2 z! Y5 z8 ~7 y }2 `8 ]1 u9 \) F1 W/ e$ j7 Z$ F
catch( _com_error & pComError )
1 ^7 M% [, @% D, W/ K6 E {( A6 g) _. t! w+ T8 ^2 C
…… // 错误处理 J! m7 w* |- G# S* W/ R
return E_UNEXPECTED;
+ @) X# Y$ B$ v' ^! v( A3 E }
* g7 X8 S& s( W! v; p}
/ y$ U# o3 N4 Y- {: E6 ?! \- t' l9 V0 g( y
9 a# o+ k- r& l2 H9 Q4.执行一个SQL 查询,得到数据集(recordset) c8 J. R- i# p: J* _6 A
; U& g. _; \* A& ~8 W_RecordsetPtr GetRecordSet( LPSTR strSql, _ConnectionPtr ptrConn )
% Z: o* N) @* G y2 m{
# ]( I% R7 v" o" i* a4 R try
/ w# P, Z! v5 |6 h5 S4 I @ {4 Q4 q# o: F/ F! O
RecordsetPtr ptrRS; // recordset 对象 q9 S! { }& K, R
& n6 n& P* z U( x" r6 v, T
// 创建recordset 对象实体
* p [, w2 k0 `+ t" I; n& C ptrRS.CreateInstance( __uuidof(Recordset) );' c, {1 i4 Q# J0 ]. z1 l
ptrRS->Open( strSql, ptrConn.GetInterfacePtr(), adOpenForwardOnly, 7 z3 {! s; c8 E0 q; H% Q
adLockUnspecified, adCmdText );
& D7 ]6 s7 S1 K% `! y7 x3 ]+ [. E# B! S' J0 x" ?5 J
或者( R3 [# q1 n' H1 m7 ?
ptrRS = ptrConn ->Execute( m_ strSql,NULL, adCmdText );
! \- n5 l! f* x7 u0 s return ptrRS;7 B! J# C8 y6 ^. S+ S6 D
}
4 ~; f$ s% x7 l/ H w" G catch( _com_error & a_pComError )$ a( M7 L# O+ c( x
{
* D$ h6 L! L' ^: Q# z* l8 o ….// 错误处理5 H, Z' V9 T& C, ~7 M K4 R
return NULL;
2 S, [' b- |* V }. |( Z4 O7 b+ Z- c U
}& O. H: y' R1 A6 n
8 q" |$ q. o. `5 ` C
; f( [! ?# r/ @) U1 h* V* j, }, ]5.通过数据集(recordset)得到列的名称
+ a+ p. w8 P6 o, `0 o4 Q5 { @. ?" b; [! d
HRESULT GetColumnNames( _RecordsetPtr ptrRs, // recordset 对象% u- i1 I( N# s8 ]
char strColNames[][255],
5 \& G$ x1 l# a. ^9 a, k1 M9 o DataTypeEnum iColTypes[] )% o" I6 x9 {0 S- j) ]. l- ~- b
{
7 _7 M4 P& \$ r" g! X) ?5 @ try
6 \: Y Z' N S* J* z/ _ { // 参数变量
; N% S- F3 f5 G; f4 y: J/ C/ S _variant_t l_vaIndex; J% N5 _9 r. G
& o& |* o8 I$ T9 z l_vaIndex.vt = VT_I2;0 p( R: ^2 H- \
$ r$ ^3 J8 {0 d4 `& E8 N6 Q
// COLUMNS总数
4 O! T }7 h/ V& A' h. e long lColCount;* x. E0 x4 K$ f/ h' L, ~
$ q+ `* D8 t' X# n# K lColCount = ptrRs ->Fields->Count;0 V0 q: Y6 e6 |0 D, z) j" M
$ f" Y: T6 t) U$ e4 u! t! b) {$ h
// 循环取得列的属性和名称4 r7 d- ]# f0 W; ^
for( int iIndex = 0 ; iIndex < lColCount; iIndex++ )0 N! L3 u, F% A5 m# @2 e
{# l. K+ n0 u q
l_vaIndex.iVal = iIndex; // 设置循环索引' I9 w6 ]! [! g* o
7 O7 R, m9 |' e8 ?9 C' ~ // 取得字段名称
% t8 a+ b+ X. p4 S+ g( b5 m$ g7 W& o sprintf(strColNames[iIndex], "%s", (LPSTR)ptrRs ->Fields->GetItem(l_vaIndex)->Name);
. ?+ |0 \: J& I9 V$ ]3 w8 ^2 C5 x
// 取得字段属性
8 x" `; F- N( Q iColTypes = ptrRs ->Fields->GetItem(l_vaIndex)->Type;/ `" o: C+ K- @ q, n, Q
}1 Z7 d0 @/ a9 G
return S_OK;* n7 S ]7 l4 h9 G! i
}
+ S5 j' Q- g+ g7 T. z7 C catch( _com_error & a_pComError )
9 {, v6 C$ ~: y: e0 x {
' l- w9 n; P3 M/ E/ ?0 a. U …. // 错误处理
8 P# M$ q% Q+ |# R& Z return E_UNEXPECTED;6 w$ q/ b' A8 ]: \( {+ ?
}
# t) E$ |; e) e8 m; `- |7 d& J catch(...)" m+ p9 ]# r9 ~ v; B1 I
{7 `) M, ?' `) ]8 Z
…. // 错误处理( L- v. h" k1 O) E. G. S; r! J
return E_UNEXPECTED;8 G. Z5 \% z- N0 c( ?' q
}
# i* a5 ?$ U% a}% q' n, @* n. M+ z5 L3 K/ V. z7 y
) A/ }5 ?' v7 F6 {
( L5 ~# X, V j8 V( |4 q6.通过数据集(recordset)得到当前行记录1 e& R3 R( ]& w4 C6 @9 D
$ ?1 \$ u! I5 e4 G8 A# W
HRESULT getOneRecord( _RecordsetPtr ptrRs,/ I8 ?" f% L* h) w' j
const long lNoOfColumns,
, L* B2 C4 _" ~4 X. N _variant_t varValue[] )
7 N- ^& S, |, k9 ]& A+ S, u{
1 A* U2 z+ y- | try5 v! C7 W8 N% d: S m
{4 s/ u6 t) }6 ^1 r
// 参数变量
4 h3 [8 {* m9 N _variant_t l_vaIndex;) r* h7 K7 v7 c4 C- {: M( g
l_vaIndex.vt = VT_I2;* R4 k* a( M, f7 m
0 F& R) Q% a0 H8 q& s0 R$ O/ U // 循环取得列的值
' m6 s) ]* u4 V, x& s4 A' T/ {. ] for( long lIndex = 0; lIndex < lNoOfColumns; lIndex++ )$ N( K2 i+ N5 r; H' l! F7 j$ F2 O! a
{
) E( I/ T5 U0 Y+ q3 M, y. Y* d l_vaIndex.iVal = lIndex;2 r" t8 m2 R7 n
3 _" {: D) Y, z7 X1 y& b3 ^$ C // 取得字段值. m0 X- z# F, _
varValue[lIndex] = ptrRs->Fields->GetItem(l_vaIndex)->Value;+ T" Z1 U; H7 F* m% c$ b
}
3 E! }/ `* I, y/ n& G9 ` return S_OK;
) L6 @: Q( S6 B( |5 ]5 o }8 h: c# Z$ k9 w e
catch( _com_error & a_pComError )
, e- [# A4 C* J9 c$ ^5 I6 j! ^7 i( i( ~ {
$ `* P7 x7 m4 V5 q! F5 X …. // 错误处理
5 E/ c+ ?; a: [0 `% e return E_UNEXPECTED;+ ?: d' U4 \1 P
}
n J# h( ~0 ^! I: m( ]6 X catch(...)- c' K/ u8 ~( l$ C& S& _+ D3 y6 D
{" U+ X' b0 t: P4 b+ s
…. // 错误处理! r3 q' L3 b' ?+ Z7 y6 l4 w9 a
return E_UNEXPECTED;$ {) F& o8 A. R. {# t
}
7 L" c8 W& F4 g& d% P}
4 A5 @$ }. E/ ^5 B& T: \1 D: r. R9 _1 h6 V$ _. G9 U, L; p) I; Q8 M
0 y; z/ O, L+ W" W7.出错情况下错误信息的取得
' L, j5 b" W$ F: d' J, g, ~
1 S( R ?- x7 L/ u: ^void ErrorFunc( _com_error &pComError, _ConnectionPtr ptrConn );
r/ V$ a. M- X3 a{
{/ p2 s) ^: V" d; F1 U // COM 错误取得0 O+ S# b7 f' I& a2 A- `: P: R
// 当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
* ~9 j8 Q+ m& `: }! f2 \0 s char lpComErrorStr512];
" f, \. ~& Q0 x5 s/ M+ b K' @- e: Y9 n7 k6 o, I3 c
sprintf( lpComErrorStr512,
# X% _! u+ ?0 D "ErrorCode = %08lx \ Error Message = %s \ Source = %s \ Description = %s ",3 B+ |0 E8 |/ z6 V- n! F& H
pComError.Error(), // 错误编号
/ r# U* p' Z2 W$ [- F, g/ l pComError.ErrorMessage(), // 错误信息
) \% d+ N* t9 [$ q; ]9 | (LPCSTR) pComError.Source(), // 错误源
9 T9 S( h) } v. M (LPCSTR) pComError.Description() ); // 错误描述
% e' H3 A4 ?! ~" n$ X- X- b8 L* B; h0 g: p/ Z0 \* ^% z/ A
// 通过上面的代码我们可以看出,_com_error对象中可以得到COM所有出错的信息
+ |9 a" ]! x, G" O/ B! u' ` // ADO错误取得
. p/ W3 ~) Z8 `5 g) O; R0 U. ~3 g2 ^% K# R$ K/ p& Z% L
ErrorPtr pErr = NULL;# Z2 h% f0 ?/ L- [, }) @5 Z
if( (ptrConn ->Errors->Count) > 0)
( W; v/ g6 b# A# J7 h; V/ | {
, G5 _4 V7 i: O2 [1 I long nCount = ptrConn ->Errors->Count;. `0 c7 @9 W- M$ `' i* S+ M+ z
for( long i = 0; i < nCount; i++ )
% u! M7 `5 `' r0 D {8 Z- ?) T) \$ p6 H3 L
pErr = a_pConnPtr->Errors->GetItem(i);
0 U' A: h! D$ E% e
# T9 }. u3 z8 W. x4 E. o/ z' I7 u- f char l_pchErrorString[512]; P) x6 H1 H3 Z* E) x( r6 O
sprintf( l_pchErrorString,"Error:\n Error number: %x\t%s",- v- v2 { j: [1 p; n* Z2 j
pErr->Number, // 错误编号) \4 r% h7 C3 v6 q; I$ H* Y
pErr->Description ); // 错误描述
9 E6 R( H- |8 _ }
. p% m( _( r3 }$ W% m' _) O, {3 N }3 [7 ?. W1 \0 D
+ Z0 M! e( [0 V: r" S% r2 Z
// ADO 处理出错的情况下, 在connection对象里面都有记录,可以通过访问! t# B, l# K/ T
// connection 对象取得错误编号和错误信息。 |
|