用户登录  |  用户注册
首 页商业源码原创产品编程论坛
当前位置:PB创新网文章中心编程技巧Visual C++

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

减小字体 增大字体 作者:佚名  来源:本站整理  发布时间:2009-03-16 20:29:24

                              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_BINDINGEND_ADO_BINDING 宏之间的绑定条目用括号括起。不要在绑定条目结尾使用逗号或分号,这些定界符仅限在宏中使用。

为每个将被转换为 C/C++ 变量的字段指定一个绑定条目。使用适当的 ADO_FIXED_LENGTH_BINDING_ENTRYADO_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>// forwardsclass 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 FilesCommon FilesSystemADOmsado15.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 FilesCommon FilesSystemADOmsado15.dll"    no_namespace rename("EOF", "EndOfFile")#include <stdio.h>#include "icrsint.h"void dump_com_error(_com_error &e)   {printf("Error");printf("aCode = %08lx", e.Error());printf("aCode meaning = %s", e.ErrorMessage());_bstr_t bstrSource(e.Source());_bstr_t bstrDescription(e.Description());printf("aSource = %s", (LPCSTR) bstrSource);printf("aDescription = %s", (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("aName = %s %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();   };

Tags:

作者:佚名

文章评论评论内容只代表网友观点,与本站立场无关!

   评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
PB创新网ourmis.com】Copyright © 2000-2009 . All Rights Reserved .
页面执行时间:26,250.00000 毫秒
Email:ourmis@126.com QQ:2322888 蜀ICP备05006790号