VC++程序员如何使用ADO?
作者:bfbd
2002 年 1 月
摘要:介绍 Microsoft(R) ActiveX(R) Data Objects (ADO) 在Visual C++中的使用,以及关于Visual C++ Extensions for ADO的讨论。
ADO就不用我介绍了吧,地球人都知道。我这里要介绍的是它在VC++中三种不同的使用方法。
第一种是直接使用控件,
第二种是各种文章介绍的最多的智能指针操作,
第三种则是笔者向大家极力推崇的Visual C++ Extensions for ADO,
另外,ADO既然是COM,也可以使用标准的调用com接口的方式使用它。
一、直接使用控件:
就是普通的OCX控件操作,简单的要命。
首先选中菜单Project->Add To Project->Components And Control…,在对话框中选中Registered ActiveX Controls目录下的Microsoft ADO Data Control 6.0 (SP4) (OLEDB)然后点击Insert,把ADO控件的类文件导入到当前工程之中。此时你的控件工具条(Controls工具条)上就多了一个浅绿色的控件,把拖到你的对话框中,……(作者此处删去500字)。
需要注意的是不要忘记包含各个导入类的头文件,否则编译通不过。
二、使用ADO的智能指针:
虽然相关介绍满天飞,为了保持文章的完整,还是简单介绍一下吧!
首先要在CMyApp::InitInstance()函数中加入
//初始化Com环境
if ( FAILED(::CoInitialize(NULL)) ) {
::AfxMessageBox( "Com Init Fail !" );
::exit(0);
}
在CMyApp::ExitInstance()函数中加入
::CoUninitialize();
然后引入ADO库文件,一般是在stdAfx.h文件中添加
#import <msado15.dll> no_namespace rename( "EOF", "adoEOF" )
这条语句会在工程所在目录生成msado15.tlh和msado15.tli两个文件。
在你的类声明文件中加入智能指针对象实例的定义,做为成员变量,
_ConnectionPtr m_pConn;
_RecordsetPtr m_pRs;
使用之前先初始化,
//初始化ADO成员
TESTHR( m_pConn.CreateInstance( __uuidof( Connection ) ) );
TESTHR( m_pRs.CreateInstance( __uuidof( Recordset ) ) );
其中TESTHR定义如下:
void TESTHR(HRESULT x) {
if FAILED(x)
_com_issue_error(x);
};①
然后就是连接数据库,获取Recordset……用不着我多说了吧,代码如下:
//Open Connection
TESTHR( m_pConn->Open( strConn/*连接字符串*/, "", "", adConnectUnspecified ) );
//Open table
TESTHR( m_pRs->Open( SQL/*SQL查询语句*/
_variant_t((IDispatch*)m_pConn, true),
adOpenKeyset,//adOpenForwardOnly,
adLockReadOnly,
adCmdText) );
三、使用Visual C++ Extensions for ADO(以下简称ADO Extensions)操作数据表。
这东东是专为VC++程序言准备的,笔者认为使用起来很方便。可遗憾的是相关介绍少之又少,连微软的MSDN上也只是寥寥数笔,真让人摸不着头脑。所以老衲只好根据自己的使用经验斗胆给大家讲讲了(莫笑哦!)。
要使用ADO Extensions 首先要完成以上第二种方法的所有步骤,实现ADO的智能指针调用,然后再实现一个IADORecordBinding类型的指针,用它将一个Recordset和一个定义好的类绑定到一起,这样你就可以象操作C++的类一样操作数据表了,还免去了自己处理VARIANT变量类型的诸多不便。
首先定义一个与数据表相对应的类,用于绑定,
#include <icrsint.h> //Head File Of IADORecordBinding
class CTabClass : public CADORecordBinding
{
BEGIN_ADO_BINDING(CTabClass)
ADO_NUMERIC_ENTRY ( 1, adDecimal, m_nWID, 38/*精度*/, 0/*小数位*/, s_nWID, false)②
//( 列序号,字段类型,缓冲区,…)
ADO_VARIABLE_LENGTH_ENTRY2( 2, adVarChar, m_Word, sizeof(m_Word), s_Word, TRUE)
ADO_FIXED_LENGTH_ENTRY ( 3, adSmallInt, m_nLWord, s_nLWord, TRUE)
ADO_VARIABLE_LENGTH_ENTRY2( 4, adChar, m_Attr, sizeof(m_Attr), s_Attr, TRUE)
ADO_FIXED_LENGTH_ENTRY ( 7, adInteger, m_nType, s_nType, TRUE)
END_ADO_BINDING()
public:
//与各字段对应的变量
DECIMAL m_nWID;
CHAR m_Word[MAX_WORD+1];
INT m_nLWord;
INT m_nType;
CHAR m_Attr[MAX_ATTR+1];
//以上各变量绑定后的状态
ULONG s_nWID;
ULONG s_nLWord;
ULONG s_Word;
ULONG s_Attr;
ULONG s_nType;
public:
//成员函数
CTabWord()
{
InitTab();
}
void InitTab(); //初始化各成员变量的值。
};
这里顺便再提一句:IADORecordBinding与IRecordset是由同一个类实现的不同接口,所以当你移动的记录指针时不要忘记另一个接口的记录指针也被移动了。
①:这个函数的定义是从网上学来的,早已不知出处。在对作者此致以诚挚的谢意,并希望各位网友能提出更好的处理方法。
②:这个绑定是笔者好不容易才找到的,在CSDN发了N个帖子也没人回应,结果找来找去发现VC自带一个DECIMAL数据类型,还有一大堆相应的类型转换函数。呵呵!知者不难,难者不知也。