请问:ADO VC++ Extentions是什么东西,怎么用呀??

解决方案 »

  1.   

    如何使用VC++对ADO的扩展IADORecordBinding接口
    VC++对ADO的扩展联系或绑定了一个Recordset对象的各个字段到C/C++变量。当被绑定的Recordset的当前行改变时,其中所有被绑定的字段的值也同样会被拷贝到相应的C/C++变量中。如果需要,被拷贝的数据还会自动进行相应的数据类型转换。
    IADORecordBinding接口的BindToRecordset方法将字段绑定到C/C++变量之上。AddNew方法则是增加一个新的行到被绑定的Recordset。Update方法利用C/C++变量的值填充Recordset中新的行或更新已存在的行。
    IADORecordBinding接口由Recordset对象实现,你不需要自己编码进行实现。绑定条目
    VC++对ADO的扩展在一个Recordset对象与一个C/C++变量间进行映像(Map)。一个字段与对应的一个变量间的映像被称作一个绑定条目。预定义的宏为数字、定长或不定长数据提供了绑定条目。所有的绑定条目与相应的C/C++变量都被封装、声明在一个从VC++扩展类CADORecordBinding派生的类中。这个CADORecordBinding类在内部由绑定条目宏定义。
    在ADO内部,将所有宏的参数都映射在一个OLE DB DBBINDING结构中,并创建一个OLE DB访问子(Accessor)对象来管理所有的行为和字段与变量间的数据转换。OLE DB定义的数据由以下三部分组成:存储数据的缓冲区;一个状态值表示一个字段是否被成功地被存入缓冲区,或变量值是否被成功地存入字段;数据长度。(参见OLE DB程序员参考第6章:读写数据的更多信息)所需的头文件
    为了使用VC++对ADO的扩展,你得在你的应用中包含这个头文件:#include <icrsint.h>绑定Recordset的字段
    要绑定Recordset的字段到C/C++变量,需要这样做: 
    1.创建一个CADORecordsetBinding的派生类。
    2.在派生类中定义绑定条目和相应的C/C++变量。注意不要使用逗号、分号切断宏。每个宏都会自动地定义适当的分隔符。
    为每个被映像的字段定义一个绑定条目。并注意根据不同情况选用ADO_FIXED_LENGTH_ENTRY、 ADO_NUMERIC_ENTRY、ADO_VARIABLE_LENGTH_ENTRY中的某个宏。
    3.在你的应用中,创建一个该派生类的实例。从Recordset中获得IADORecordBinding接口,然后调用BindToRecordset方法将Recordset的所有字段绑定到对应的C/C++变量之上。
    请参见示例程序以获得更多信息。接口方法
    IADORecordBinding接口只有三个方法:BindToRecordset, AddNew,和Update。每个方法所需的唯一的参数就是一个CADORecordBinding派生类的实例指针。因此,AddNew和Update方法不能使用任何与它们同名的ADO方法中的参数。语法
    BindToRecordset方法将字段绑定到C/C++变量之上。
    BindToRecordset(CADORecordBinding *binding)
    AddNew方法则引用了它的同名ADO函数,来增加一个新的记录行。
    AddNew(CADORecordBinding *binding)
    Update方法也引用了它的同名ADO函数,来更新Recordset。
    Update(CADORecordBinding *binding)绑定条目宏
    绑定条目宏定义了一个Recordset字段与一个变量间的对应关系。每个条目的绑定宏由开始宏与结束宏组成并配对使用。
    定长数据的宏适用于adDate,adBoolean等,数字的宏适用于adTinyInt, adInteger和adDouble等,变长数据的宏适用于adChar, adVarChar和adVarBinary等。所有的数字类型,除了adVarNumeric以外也是定长数据类型。每个宏的族之间都有不同的参数组,因此你可以排除不感兴趣的绑定信息。
    参见OLE DB程序员参考附录A:数据类型的更多信息开始绑定条目
    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 派生类的名字。
    Ordinal 从1开始的序号,对应于Recordset中的字段。
    DataType 与C/C++变量对应的ADO数据类型(参见DataTypeEnum以获得有效数据类型的列表)。如果需要,字段的值会被转换成该类型的值。
    Buffer 对应的C/C++变量的名字。
    Size 该C/C++变量的最大字节数。如果是个变长字符串,使用0表示即可。
    Status 指示变量的名字。该变量用以表示缓冲是否有效,数据转换是否成功。
    值adFldOK意味着转换成功;adFldNull意味着该字段的值为空。其他可能的值见后面的状态值列表。
    Modify 逻辑标志。TRUE意味着ADO允许利用变量值更新Recordset中的字段的值。
    设置该值为TRUE将允许更新,如果你只想检查字段的值而不想改变它那么就设置为FALSE。
    Precision 数字型变量的位数。
    Scale 数字型变量的小数位数。
    Length 一个4字节变量的名字。该变量将包含缓冲区中数据的实际长度。状态值
    变量Status的值指示了一个字段的值是否被成功的拷贝到了对应的变量中。写数据时,可以给Status赋值为adFldNull来指示该字段将被设置为null。
    常量 值 描述
    adFldOK 0 一个非空的字段值被返回。
    adFldBadAccessor 1 绑定无效。
    adFldCantConvertValue 2 值因为符号不匹配或超界外的原因导致无法被正确转换。
    adFldNull 3 读字段值时,指示一个空值被返回。写字段值时,指示当字段自身无法编码NULL时该字段将被设置为NULL。
    adFldTruncated 4 变长数据或数字被截断。
    adFldSignMismatch 5 值是有符号数,而数据类型是无符号数。
    adFldDataOverFlow 6 数据值超出界限。
    adFldCantCreate 7 不知名的列类型和字段已经被打开。
    adFldUnavailable 8 字段值无法确定。比如一个新的未赋值的无缺省值的字段。
    adFldPermissionDenied 9 未被允许更新数据。
    adFldIntegrityViolation 10 更新字段时值违反了列的完整性要求。
    adFldSchemaViolation 11 更新字段时值违反了列的规范要求。
    adFldBadStatus 12 更新字段时,无效的状态参数。
    adFldDefault 13 更新字段时,使用缺省值。使用VC++对ADO的扩展的示例
    在这个例子中,还使用了COM专有的“智能指针”功能,它能自动处理IADORecordBinding接口的QueryInterface和引用计数。如果没有智能指针,你得这样编码:
    IADORecordBinding   *picRs = NULL;
    ...
    TESTHR(pRs->QueryInterface(
              __uuidof(IADORecordBinding), (LPVOID*)&picRs));
    ...
    if (picRs) picRs->Release();
    使用智能指针,你可以用这样的语句从IADORecordBinding接口派生IADORecordBindingPtr类型:
    _COM_SMARTPTR_TYPEDEF(IADORecordBinding, __uuidof(IADORecordBinding));
    然后这样实例化指针:
    IADORecordBindingPtr picRs(pRs);
    因为VC++的扩展由Recordset对象实现,因此智能指针picRs的构造函数使用了_RecordsetPtr类指针pRs。构造函数利用pRs调用QueryInterface来获得IADORecordBinding接口。// 以下即是示例程序
    #import "c:\Program Files\Common Files\System\ADO\msado15.dll" \
       no_namespace rename("EOF", "EndOfFile")#include <stdio.h>
    #include <icrsint.h>
    _COM_SMARTPTR_TYPEDEF(IADORecordBinding, __uuidof(IADORecordBinding));inline void TESTHR(HRESULT _hr) { if FAILED(_hr) _com_issue_error(_hr); }class CCustomRs : public CADORecordBinding
    {
    BEGIN_ADO_BINDING(CCustomRs)
       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()
    public:
       CHAR    m_ch_fname[22];
       CHAR    m_ch_lname[32];
       ULONG   m_ul_fnameStatus;
       ULONG   m_ul_lnameStatus;
    };void main(void)
    {
       ::CoInitialize(NULL);
       try 
          {
          _RecordsetPtr pRs("ADODB.Recordset");
          CCustomRs rs;
          IADORecordBindingPtr picRs(pRs);
          
          pRs->Open("SELECT * FROM Employee ORDER BY lname", 
             "dsn=pubs;uid=sa;pwd=;", 
             adOpenStatic, adLockOptimistic, adCmdText);
          
          TESTHR(picRs->BindToRecordset(&rs));      while (!pRs->EndOfFile)
             {
          // 处理CCustomRs中的数据
             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>"));      // 移动到下一行,新行的值会被自动填充到对应的CCustomRs的变量中 
             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());
          }
       ::CoUninitialize();
    }