分享
 
 
 

理解 Visual C++ Extensions for ADO

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

【前言】

当我们使用Visual C++进行ADO编程时,一项颇为头疼的工作就是对VARIANT字段类型的处理。通常做法是,先把VARIANT类型转换为形式上较为类似的C++类型,然后再把转换后的数据存放在一个类(class)或结构(structure)中。即便如此,对VARIANT数据类型的处理在一定程度上也影响到了程序的性能。

ADO为我们提供了一个接口,该接口使我们可以把数据直接读取到本地,从而绕开对于复杂的VARIANT数据类型的处理。同时,ADO还定义了一组预处理宏,用来简化接口的使用。用好这一工具,将会使我们的编程工作将变得轻松和高效。

一般情况下,我们从ADO获得Recordset数据集,然后定义一个C/C++结构类型,再把Recordset中的记录绑定到结构成员变量中。当遇到VARIANT类型时,情况变得复杂,你必须解决如何把VARIANT数据类型(数据库)转换到C/C++数据类型(本地)的问题。Visual C++ Extensions for ADO(为叙述方便,以下简称ADOExt)的目标就是使这一切变得简单。

【IADORecordBinding 接口简介】

ADOExt 把RecordSet记录集中的字段绑定到C/C++变量中。一旦该Recordset当前行的数据发生改变,数据将被立即拷贝到绑定的C/C++变量中。根据需要,数据将被转换到指定的C/C++数据类型。

IADORecordBinding 接口的 BindToRecordset 成员方法用来实现数据库字段到本地C/C++变量之间的绑定。如果要为Recordset新增一条记录,可以使用AddNew方法。Update方法则用来把绑定的C/C++变量数据更新和升级到数据库中。

IADORecordBinding 接口的实现不用我们操心,Recordset对象悄悄的在幕后完成这一切。

【绑定单元(Binding Entries)简介】

ADOExt 把Recordset对象的字段类型映射到本地的C/C++变量中,我们把这种从一个数据库字段映射到一个C/C++变量之间的过程定义称为一个绑定单元(Binding Entries)。绑定由宏来完成,可以绑定的类型包括数值型、定长、以及可变长度的数据。绑定的基本流程是:定义派生自CADORecordBinding(CADORecordBinding 类本身其实也是一组宏定义)的类,在类中使用特定的宏来实现数据绑定。然后,在类中声明相应的C/C++变量。

ADO 在内部把宏定义中的参数映射到一个OLE DB DBBINDING类型的结构中,并且创建一个OLE DB 存取对象用来管理字段和变量之间的数据移动和格式转换。OLE DB 的数据定义包括三个部分:一个用来储存数据的缓冲区;一个用来标示数据存取状态,以及变量如何提取的状态位;以及数据的长度。

【头文件包含】

要使用 Visual C++ 的ADOExt, 你需要在应用程序中包含下列头文件:

#include <icrsint.h>

【绑定Recordset 字段的过程】

■创建一个派生自CADORecordsetBinding的类。

■在派生类中设定绑定单元并定义相应的C/C++变量。这些绑定单元被界定在 BEGIN_ADO_BINDING 和 END_ADO_BINDING 之间。不要想当然的在宏定义间放置逗号或者分号,这些工作会由宏在内部自动实现。

■为每一个要映射为C/C++变量的数据库字段指定一个绑定单元。根据需要从ADO_FIXED_LENGTH_ENTRY, ADO_NUMERIC_ENTRY, 或者 ADO_VARIABLE_LENGTH_ENTRY 这三个宏定义中选择一个,并填写上正确的参数。

■在你的引用程序中,创建一个该类的实例。从 Recordset 中获取 IADORecordBinding 接口。然后调用BindToRecordset方法实现数据绑定。

【接口方法定义】

IADORecordBinding 接口有三个方法:BindToRecordset, AddNew, 以及 Update。这些方法有且只有一个指针类型的参数,该参数指向一个派生自CADORecordBinding的类实例。事实上,AddNew 和 Updage 方法 将分别调用 ADO 中的同名方法。

语法:

BindToRecordset 方法实现 Recordset 字段到 C/C++ 变量之间的绑定。

BindToRecordset(CADORecordBinding *binding)

AddNew 方法调用它的同名方法,ADO 中的 AddNew 方法,向 Recordset 中增加一条新的记录。

AddNew(CADORecordBinding *binding)

Update 方法调用它在ADO中的同名方法 Update, 完成对Recordset的数据更新。

Update(CADORecordBinding *binding)

【理解绑定单元中的宏】

绑定单元定义了Recordset字段和变量之间的联系。 宏BEGIN_ADO_BINDING(Class)(开始宏)和END_ADO_BINDING()(结束宏)界定了一组绑定单元。

绑定单元中的宏提供了对于下列字段类型的支持:

■定长类型的数据。例如 adDate 或 adBoolean

■数值型数据。例如 adTinyInt, adInteger, 以及 adDouble

■变长类型的数据。例如 adChar, adVarChar 以及 adVarBinary

所有的数值型数据,除了 adVarNumeric 类型之外,同时也都是定长类型的数据。

不同的宏定义使用不同类型的参数,这样你就可以排除不感兴趣的绑定信息。

■开始数据绑定

BEGIN_ADO_BINDING(Class)

■定长类型的数据

ADO_FIXED_LENGTH_ENTRY(Ordinal, DataType, Buffer, Status, Modify)

ADO_FIXED_LENGTH_ENTRY2(Ordinal, DataType, Buffer, Modify)

■数值型数据

ADO_NUMERIC_ENTRY(Ordinal, DataType, Buffer, Precision, Scale, Status, Modify)

ADO_NUMERIC_ENTRY2(Ordinal, DataType, Buffer, Precision, Scale, Modify)

■可变长度类型的数据

ADO_VARIABLE_LENGTH_ENTRY(Ordinal, DataType, Buffer, Size, Status, Length, Modify)

ADO_VARIABLE_LENGTH_ENTRY2(Ordinal, DataType, Buffer, Size, Status, Modify)

ADO_VARIABLE_LENGTH_ENTRY3(Ordinal, DataType, Buffer, Size, Length, Modify)

ADO_VARIABLE_LENGTH_ENTRY4(Ordinal, DataType, Buffer, Size, Modify)

■结束数据绑定

END_ADO_BINDING()

---------------------------------------------------

参数:描述

Class:绑定单元和C/C++变量定义所在的类。

Ordinal:序数类型,从1开始计数的Recordset字段序号,该字段对应于指定的C/C++变量。

DataType: 和ADO中的数据类型等价的C/C++数据类型。相应的Recordset字段在需要时将转换为该数据类型。

Buffer:用来存储Recordset字段的缓冲区名称。

Size:缓冲区的最大尺寸。

Status:状态位。指示缓冲区的内容的有效性,以及字段转换是否成功。其中有两个比较重要的值。一个是adFldOK, 表明转换是成功的;另一个是adFldNull, 表明字段值为NULL。更多的状态值,请参考MSDN

Modify:布尔类型。如果为TRUE, 表明ADO允许更新缓冲区中的数据。如果为FALSE,表明数据是只读的。

Precision:数值类型的精度。

Scale:数值类型的小数位数。Number of decimal places in a numeric variable.

Length: 一个四字节的变量。用来包含缓冲区中数据的实际长度。

----------------------------------------------------

【Visual C++ Extensions 例程】

//引入msado15.dll文件,从而声明了ADO类型库

#import "c:\Program Files\Common Files\System\ADO\msado15.dll" no_namespace rename("EOF", "EndOfFile")

#include <stdio.h>

#include <icrsint.h> //在此处包含icrsint.h头文件

//_COM_SMARTPTR_TYPEDEF 宏定义了一个_com_ptr_t类型的智能(smart)指针IADORecordBingingPtr

_COM_SMARTPTR_TYPEDEF(IADORecordBinding, __uuidof(IADORecordBinding));

//定义一个测试函数

inline void TESTHR(HRESULT _hr) { if FAILED(_hr) _com_issue_error(_hr); }

//定义一个派生自CADORecordBinding的类

class CCustomRs : public CADORecordBinding

{

//开始进行数据类型绑定

BEGIN_ADO_BINDING(CCustomRs)

//把Recordset的第2个adVarChar类型的字段绑定到C/C++变量m_ch_fname上

ADO_VARIABLE_LENGTH_ENTRY2(2, adVarChar, m_ch_fname,

sizeof(m_ch_fname), m_ul_fnameStatus, false)

ADO_VARIABLE_LENGTH_ENTRY2(4, adVarChar, m_ch_lname,

sizeof(m_ch_lname), m_ul_lnameStatus, false)

//结束绑定

END_ADO_BINDING()

//紧接着定义上述宏中用到的C/C++变量

public:

CHAR m_ch_fname[22];

CHAR m_ch_lname[32];

ULONG m_ul_fnameStatus;

ULONG m_ul_lnameStatus;

};

//开始程序执行

void main(void)

{

::CoInitialize(NULL); //初始化COM对象

try

{

//typedef _com_ptr_t<_Recordset, __uuidof(_Recordset)> _RecordsetPtr:指向一个_Recordset的智能指针

_RecordsetPtr pRs("ADODB.Recordset");

//定义一个CCustomRS: public CADORecordBinding类的实例

CCustomRs rs;

//把IADORecordBindingPtr接口类型对象picRs指定到pRs对象,从而实现接口和对象之间的关联

IADORecordBindingPtr picRs(pRs);

//调用_Recordset的Open方法取得Recordset对象

pRs->Open("SELECT * FROM Employee ORDER BY lname",

"dsn=pubs;uid=sa;pwd=;",

adOpenStatic, adLockOptimistic, adCmdText);

//利用CCustomRS类中的宏定义,实现数据之间的绑定

//如果绑定成功,我们就可以使用rs对象的属性了

TESTHR(picRs->BindToRecordset(&rs));

//大家注意,这里的EndOfFile对应上文import语句中的rename("EOF", "EndOfFile"),其实就是EOF。rename的作用为了防止命名冲突。

while (!pRs->EndOfFile)

{

// Process data in the CCustomRs C++ instance variables.

printf("Name = %s %s\n",

(rs.m_ul_fnameStatus == adFldOK ? rs.m_ch_fname: "<Error>"),

(rs.m_ul_lnameStatus == adFldOK ? rs.m_ch_lname: "<Error>"));

// Move to the next row of the Recordset.

// Fields in the new row will automatically be

// placed in the CCustomRs C++ instance variables.

pRs->MoveNext();

}

}

catch (_com_error &e )

{

printf("Error:\n");

printf("Code = %08lx\n", e.Error());

printf("Meaning = %s\n", e.ErrorMessage());

printf("Source = %s\n", (LPCSTR) e.Source());

printf("Description = %s\n", (LPCSTR) e.Description());

}

//清除COM对象实例

::CoUninitialize();

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有