分享
 
 
 

ADO 的 VC++ Extensions(简化VARIANT 与C++ 数据类型的烦琐转化,附源代码)

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

ADO 的 VC++ Extensions

当用 ADO 检索数据时,Visual C++ 程序员所面对的一个最冗长而乏味的工作是必须将以 VARIANT 数据类型返回的数据转换为 C++ 数据类型,然后将转换后的数据存入类或结构中。此外,通过 VARIANT 数据类型检索 C++ 数据的过程繁琐并有损性能。

ADO 2.0 版本提供的接口支持不通过 VARIANT 便可将数据检索到本地 C/C++ 数据类型。此外,ADO 提供的预处理宏简化了接口的使用。由此获得了这样一个灵活、易用和高性能的工具。

ADO 2.0 提供接口方法和预处理宏以简化将 Recordset 字段值转化为 C/C++ 变量的过程。

这些扩展程序使用简便并且性能良好。

总结介绍了所提供的预处理宏和接口方法。

代码范例描述了 VC++ Extensions 头文件的详细内容。

范例说明了在使用和不使用 ADO VC++ Extensions 的情况下如何转换字段值。

普通的 C/C++ 客户端方案将 Recordset 中的记录绑定到包含本地 C/C++ 类型的 C/C++ 结构/类上。使用 VARIANT 时,将涉及编写从 VARIANT 到 C/C++ 本地类型的转换代码。ADO VC++ Extensions 的目的是便于 VC++ 程序员使用上述方案。

ADO VC++ Extensions 可将 Recordset 对象的字段映射到 C/C++ 变量,字段与变量的映射称为 绑定条目 。预处理宏用来定义数值、定长和变长变量的绑定条目。

将 BEGIN_ADO_BINDING 和 END_ADO_BINDING 宏之间的绑定条目用括号括起。不要在绑定条目结尾使用逗号或分号,这些定界符仅限在宏中使用。

为每个将被转换为 C/C++ 变量的字段指定一个绑定条目。使用适当的 ADO_FIXED_LENGTH_BINDING_ENTRY , ADO_NUMERIC_BINDING_ENTRY 或 ADO_VARIABLE_LENGTH_BINDING_ENTRY 宏。

在宏的参数中,用序数指定将被提出的 Recordset 字段 — 0 标识第一字段,1 标识第二字段,依此类推。

使用数据类型声明 C/C++ 变量。如果变量为数值,也可指定精度和范围。如果变量为变长变量(如字符串),则必须以字节指定变量的最大尺寸。如果需要, Recordset 字段值可被强制为该数据类型。

指定临时的工作缓冲区,用来将字段值从 VARIANT 转换为 C/C++ 变量。缓冲区应至少与此 C/C++ 变量一样大。

将布尔型修改参数设置为 TRUE 使 ADO 可更新绑定的字段,如只检查字段而不将其更改,可设置为 FALSE。VC++ Extensions 不保留有关字段的状态信息,因此必须指定 ADO 是否更改字段值(例如,由数据源保留的自动增值字段的值)。因此该字段的修改参数应设置为 FALSE。

状态参数可告诉您从 Recordset 字段到 C 或 C++ 变量的转换是否成功以及变量的内容是否有效。该参数的两个最重要的值是 adFldOK (意味着转换成功)和 adFldNull (意味着字段是 NULL—无值可供转换)。

首先检测该参数以决定 C 或 C++ 变量是否有效。例如,如果字段具有有效的行内容,状态将会是 adFldOK ;如果移动到另一个字段为 NULL 的行,状态则将是 adFldNull 。然而,C 或 C++ 变量的内容将不被更改 — 该变量将仍然包含上一行的字段值。

将 Recordset 绑定到变量

在应用程序中,调用 BindToRecordset 接口方法可使 Recordset 字段关联(或绑定)到 C/C++ 变量,无论何时更改 Recordset 对象的当前行,C/C++ 变量都将自动更新。

头文件

要使用 VC++ Extensions,请在应用程序中包含如下文件:

#include <icrsint.h>

接口方法

IADORecordBinding 接口具有使 Recordset 字段与 C/C++ 变量关联、添加新行和执行更新的方法。所有这三个方法都可使指针指向来自 CADORecordBinding 的类,该 CADORecordBinding 定义每个字段和变量之间的绑定。

接口方法是:

BindToRecordset ( &binding )

调用该方法可关联变量与字段。

AddNew (& binding )

调用该方法可直接调用 ADO AddNew 方法。

Update (& binding )

调用该方法可直接调用 ADO Update 方法。

预处理宏

BEGIN_ADO_BINDING( cls )

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

ADO_NUMERIC_BINDING_ENTRY( Ordinal , DataType , Buffer , Precision , Scale ,

Status , Modify )

ADO_VARIABLE_LENGTH_BINDING_ENTRY( Ordinal , DataType , Buffer , Size ,

Status , Modify )

END_ADO_BINDING()

参数

说明

Cls

类,定义绑定条目,缓冲区,和 Recordset 对象。

Ordinal

按顺序的字段号码,0 标识第一字段,1 标识第二字段,依此类推。

DataType

储存已转换字段的变量的数据类型。

Buffer

缓冲区,用于将字段转换为变量。

Status

指示字段转换是否成功。

Modify

布尔标志;如果为 TRUE,则表明 ADO 可以更新关联的字段。

Precision

在数值变量中可被表现出的数字位数。

Scale

位于数值变量中的小数点后的位数。

Size

变长变量所需的字节数,诸如:字符串。

status 参数值

说明

AdFldOK

返回非 NULL 字段值。

AdFldBadAccessor

绑定无效。

AdFldCantConvertValue

由于符号不匹配和数据溢出以外的原因,值不能转换。

AdFldNull

返回 NULL。

AdFldTruncated

变长数据或数值型数字被截短。

AdFldSignMismatch

值带有符号而变量数据类型不带符号。

AdFldDataOverFlow

值大于在变量数据类型中的存储大小。

AdFldCantCreate

列类型未知并且字段已被打开。

AdFldUnavailable

不能决定字段值 — 例如在无默认值的新建、未指定的字段中。

AdFldPermissionDenied

更新时,不允许写入数据。

AdFldIntegrityViolation

更新时,字段值将破坏列的完整性。

AdFldSchemaViolation

更新时,字段值将破坏列方案。

AdFldBadStatus

更新时,无效的状态参数。

AdFldDefault

更新时,使用默认值。

VC++ Extensions 头文件的详细资料

下列头文件 (icrsint.h) 详细说明了允许客户提取一行数据并直接送至类数据成员的接口。客户程序需要在其类中包含绑定条目,以指定 Recordset Field 对象和类数据成员之间的关联。 #ifndef _ICRSINT_H_

#define _ICRSINT_H_

#include <olectl.h>

#include <stddef.h>

// forwards

class CADORecordBinding;

#define classoffset(base, derived) ((DWORD)(static_cast<base*>((derived*)8))-8)

enum FieldStatusEnum

{

adFldOK = 0,

adFldBadAccessor = 1,

adFldCantConvertValue = 2,

adFldNull = 3,

adFldTruncated = 4,

adFldSignMismatch = 5,

adFldDataOverFlow = 6,

adFldCantCreate = 7,

adFldUnavailable = 8,

adFldPermissionDenied = 9,

adFldIntegrityViolation = 10,

adFldSchemaViolation = 11,

adFldBadStatus = 12,

adFldDefault = 13

};

typedef struct stADO_BINDING_ENTRY

{

ULONG ulOrdinal;

WORD wDataType;

BYTE bPrecision;

BYTE bScale;

ULONG ulSize;

ULONG ulOffSet;

ULONG ulIADOBindingEntriesOffSet;

ULONG ulFldStatusOffset;

BOOL fModify;

} ADO_BINDING_ENTRY;

#define BEGIN_ADO_BINDING(cls) public: typedef cls ADORowClass; const ADO_BINDING_ENTRY* STDMETHODCALLTYPE GetADOBindingEntries() { static const ADO_BINDING_ENTRY rgADOBindingEntries[] = {

#define ADO_FIXED_LENGTH_BINDING_ENTRY(Ordinal, DataType, Buffer, \ Status, Modify) {Ordinal, DataType, 0, 0, 0, offsetof(ADORowClass, Buffer), classoffset(CADORecordBinding, ADORowClass), offsetof(ADORowClass, Status), Modify},

#define ADO_NUMERIC_BINDING_ENTRY(Ordinal, DataType, Buffer, Precision, Scale, Status, Modify) {Ordinal, DataType, Precision, Scale, 0, offsetof(ADORowClass, Buffer), classoffset(CADORecordBinding, ADORowClass), offsetof(ADORowClass, Status), Modify},

#define ADO_VARIABLE_LENGTH_BINDING_ENTRY(Ordinal, DataType, Buffer, Size, Status, Modify) {Ordinal, DataType, 0, 0, Size, offsetof(ADORowClass, Buffer), classoffset(CADORecordBinding, ADORowClass), offsetof(ADORowClass, Status), Modify},

#define END_ADO_BINDING() {0, adEmpty, 0, 0, 0, 0, 0, adFldOK, FALSE}}; return rgADOBindingEntries;}

//

// 客户端“记录”类需要支持的接口。

// ADO 绑定条目提供执行该接口。

//

class CADORecordBinding

{

public:

STDMETHOD_(const ADO_BINDING_ENTRY*, GetADOBindingEntries)

(VOID) PURE;

};

//

// 接口允许客户程序获取数据记录并传递给类数据成员。

//

DEFINE_GUID(IID_IADORecordBinding,

0x00000544, 0, 0x10, 0x80,0,0,0xAA,0,0x6D,0x2E,0xA4);

DECLARE_INTERFACE_(IADORecordBinding, IUnknown)

{

public:

STDMETHOD(BindToRecordset)(CADORecordBinding *pAdoRecordBinding)PURE;

STDMETHOD(AddNew)(CADORecordBinding *pAdoRecordBinding) PURE;

STDMETHOD(Update)(CADORecordBinding *pAdoRecordBinding) PURE;

};

#endif // !_ICRSINT_H_

范例: 无 Extensions 的 ADO

该程序段说明了如何从字段检索数值并将数值转换为 C++ 变量。 #import "c:\Program Files\Common Files\System\ADO\msado15.dll"

no_namespace rename("EOF", "EndOfFile")

#include <stdio.h>

Class CEmployee

{

public:

FetchEmployeeData();

char m_szFirstName[30];

char m_szLastName[30];

int nAge;

};

CEmployee::FetchEmployeeData()

{

_ConnectionPtr pCon();

_RecordsetPtr pRs();

FieldPtr pfldFirstName, pfldLastName, pfldAge;

_variant_t vFirstName, vLastName, vAge;

pCon.CreateInstance(__uuidof(Connection));

pCon->Open( “ pubs ” , “ sa ” , “” );

pRs.CreateInstance(__uuidof(Recordset));

pRs->Open( “ select FirstName, LastName, Age from Employees ” , pCon,

adOpenForwardOnly, adLockReadOnly, adCmdUnknown);

pfldFirstName = pRs->Fields->GetItem(0);

pfldLastName = pRs->Fields->GetItem(1);

pfldAge = pRs->Fields->GetItem(2);

while (VARIANT_FALSE == pRs->EndOfFile)

{

vFirstName.Clear();

vLastName.Clear();

vAge.Clear();

vFirstName = pfldFirstName->Value;

WideCharToMultiByte(CP_ACP, 0, vFirstName.bstrVal, -1,

m_szFirstName, sizeof(m_szFirstName), NULL, NULL);

vLastName = pfldLastName->Value;

WideCharToMultiByte(CP_ACP, 0, vLastName.bstrVal, -1,

m_szLastName, sizeof(m_szLastName), NULL, NULL);

nAge = vAge.iVal;

pRs->MoveNext();

}

}

范例: 带 Extensions 的 ADO

该程序说明了如何从字段检索数值并将数值转换为 C++ 变量。它包括了在程序段( 范例:无 Extensions 的 ADO )中所描述的功能。 #define INITGUID

#import "c:\Program Files\Common Files\System\ADO\msado15.dll"

no_namespace rename("EOF", "EndOfFile")

#include <stdio.h>

#include "icrsint.h"

void dump_com_error(_com_error &e)

{

printf("Error\n");

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

printf("\a\tCode meaning = %s", e.ErrorMessage());

_bstr_t bstrSource(e.Source());

_bstr_t bstrDescription(e.Description());

printf("\a\tSource = %s\n", (LPCSTR) bstrSource);

printf("\a\tDescription = %s\n", (LPCSTR) bstrDescription);

}

class CCustomRs :

public CADORecordBinding

{

BEGIN_ADO_BINDING(CCustomRs)

ADO_VARIABLE_LENGTH_BINDING_ENTRY(1, adVarChar, m_szau_lname,

sizeof(m_szau_lname), lau_lnameStatus, FALSE)

ADO_VARIABLE_LENGTH_BINDING_ENTRY(2, adVarChar, m_szau_fname,

sizeof(m_szau_fname), lau_fnameStatus, TRUE)

END_ADO_BINDING()

public:

CHAR m_szau_lname[41];

ULONG lau_lnameStatus;

CHAR m_szau_fname[41];

ULONG lau_fnameStatus;

};

VOID main()

{

HRESULT hr;

IADORecordBinding *picRs = NULL;

::CoInitialize(NULL);

try

{

_RecordsetPtr pRs.CreateInstance(__uuidof(Recordset)); CCustomRs rs;

pRs->Open("select FirstName, LastName, Age from Employees",

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

adOpenStatic, adLockOptimistic, adCmdUnknown);

if (FAILED(hr = pRs->QueryInterface(__uuidof(IADORecordBinding),

(LPVOID*)&picRs)))

_com_issue_error(hr);

if (FAILED(hr = picRs->BindToRecordset(&rs)))

_com_issue_error(hr);

while (VARIANT_FALSE == pRs->EndOfFile)

{

// 处理 CCustomRs C++ 实例变量中的数据。

printf("\a\tName = %s \t%s",

(lau_fnameStatus == adFldOK ? m_szau_fname : "<NULL>"),

(lau_lnameStatus == adFldOK ? m_szau_lname): "<NULL>"));

// 更改 Recordset 的当前行。

// 新当前行的 Recordset 数据将被

// 自动取出并防止在 CCustomRs C++ 实例变量中

pRs->MoveNext();

}

}

catch (_com_error &e)

{

dump_com_error(e);

}

if (picRs)

picRs->Release();

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- 王朝網路 版權所有