设为首页 加入收藏

TOP

VC++程序员应当如何阅读ADO文档(1)
2013-10-06 23:42:37 】 浏览:200
Tags:程序员 应当 如何 阅读 ADO 文档

《ADO API参考》用VB的语法描述了ADO API的内容。但ADO程序员却使用着不同的编程(www.cppentry.com)语言,比如VB,VC++(www.cppentry.com),VJ++。对此《ADO for VC++(www.cppentry.com)的语法索引》提供了符合VC++(www.cppentry.com)语法规范的详细描述,包括功能、参数、异常处理等等。

ADO基于若干的COM借口实现,因此它的使用对于一个正进行COM编程(www.cppentry.com)的程序员而言更简单。比如,几乎所有使用COM的细节对于VB程序员而言都是隐藏了的,但对于VC++(www.cppentry.com)程序员而言却要特别注意。以下是对于C和C++(www.cppentry.com)程序员使用ADO和#import指示符方面的概述,主要描述了COM使用的数据类型(Variant, BSTR, and SafeArray)和异常的处理(_com_error)。

使用#import编译指示符

#import编译指示符使使用ADO的方法与属性简单化。这个指示符需要一个类型库文件名,比如ADO.dll(Msado15.dll),并生成对应的头文件,其中包括定义的类型、接口的智能化指针、常量。并且所有的接口都被封装成类。

对于类中的每个操作(或称方法、属性调用),都有一个声明以保证能直接调用它(或称作操作的源形式),以及另一个声明来调用这个源操作并在操作失败时抛出一个COM错误。如果操作是一个属性,那么编译指示符可以为该操作创建一个可交互的类似VB的语法形式。

返回/设置属性的操作有对应的形式化的名字—GetProperty/PutPropert,而设置一个指向某个ADO对象的指针型属性值时则是PutRefProperty。你将使用如下的形式读写属性的值:

variable = objectPtr->GetProperty(); // 读取属性的值

objectPtr->PutProperty(value);       // 设置属性的值

objectPtr->PutRefProperty(&value);   // 设置一个指针型的属性的值

直接使用属性

__declspec(property...)编译指示符是微软定义的一个针对C语言的扩展,使一个函数象一个属性那样被使用。这样你就可以采用如下的语法形式象在使用VB一样读写一个属性的值: objectPtr->property = value;        // 设置属性的值

variable = objectPtr->property;     // 读取属性的值

__declspec(property...)编译指示符只能针对属性的读写函数使用,并根据属性是否可供读写自动生成对应的调用形式。每个属性可能有GetProperty, PutProperty,PutRefProperty三个函数,但这个编译符只能生成其中的两种交互形式。比如,Command对象的ActiveConnection属性有GetActiveConnection和PutRefActiveConnection这两个读写函数。而PutRef-的形式在实践中是个好的选择,你可以将一个活动的Connection对象的指针保存在这个属性中。另一方面,Recordset对象则有Get-, Put-, and PutRefActiveConnection操作,但却没有可交互的语法形式。

Collections,GetItem方法和Item属性

ADO定义了几种集合Collection,包括Fields,Parameters,Properties,和Errors。在Visual C++(www.cppentry.com)中,GetItem(index)方法返回Collection中的某个成员。Index是一个Variant型的参数,内容可以是一个该成员对应的序数,也可以是一个包括其名称的字符串。

__declspec(property...)编译指示符为Item属性生成对应于GetItem()方法的直接使用形式(上文提到的可交互的语法形式)。这种形式类似于引用数组元素时使用[]的语法形式:

collectionPtr->GetItem(index);

collectionPtr->Item[index];

举例说明,要给一个Recordset对象rs中的某个字段赋值,而这个Recordset对象派生于pubs数据库中的authors表。使用Item()属性访问这个Recordset的Fields集合中的第三个字段(集合总是从0开始编号,假设第三个字段名为au_fname)。然后调用Value()方法为该字段赋一个字符串值。

Visual Basic的语法形式:

rs.Fields.Item(2).Value = "value"

rs.Fields.Item("au_fname").Value = "value"

或者:

rs(2) = "value"

rs!au_fname = "value"

Visual C++(www.cppentry.com)的语法形式:

rs->Fields->GetItem(2)->PutValue("value");

rs->Fields->GetItem("au_fname")->PutValue("value");

或者:

rs->Fields->Item[2]->Value = "value";

rs->Fields->Item["au_fname"]->Value = "value";

COM特定的数据类型

一般的,你在《ADO API Reference》中看到的VB的数据类型在VC++(www.cppentry.com)中也能找到对应的类型。其中包括标准的数据类型,比如unsigned char对应VB的Byte,short对应Integer,long对应Long。参见《Syntax Indexes》将可以获得关于所需操作数的更详细内容。

而作为例外的专属于COM使用的数据类型则有:Variant, BSTR, and SafeArray.

Variant

Variant是一个结构化的数据类型,包含了一个成员值及其数据类型的表示。Variant可以表示相当多的数据类型,甚至另一个Variant, BSTR, Boolean, Idispatch或Iunknown指针,货币,日期等等。同时COM也提供了许多方法使数据类型间的转换更简单化。

_variant_t类封装并管理Variant这一数据类型。

当《ADO API Reference》中说到一个方法或属性要使用一个参数时,通常意味着需要一个_variant_t类型的参数。这条准则在《ADO API Reference》的Parameters一章中得到了明白无误的表述。作为例外的是,有时则会要求操作数是一个标准的数据类型,比如Long或Byte, 或者一个枚举值。另一个例外是要求操作数是一个字符串String。

BSTR

BSTR (Basic STRing)也是一个结构化的数据类型,包括了串及串的长度。COM提供了方法进行串的空间分配、操作、释放。

_bstr_t类封装并管理BSTR这一数据类型。

当《ADO API Reference》中说到一个方法或属性要使用一个字符串参数时,通常意味着需要一个类_bstr_t型的参数。

_variant_t和_bstr_t类的强制类型转换

通常当传递一个_variant_t或_bstr_t参数给一个操作时并不需要显式的类型转换代码。如果_variant_t或_bstr_t类提供了对应于该参数类型的构造函数,那么编译器将会自动生成适当的_variant_t或_bstr_t值。

然而,当参数模棱两可时,即对应了多个构造函数时,你就必须显式地调用正确的构造函数以获得正确的参数。比如,Recordset::Open方法的函数声明如下:

    HRESULT Open (

        const _variant_t & Source,

        const _variant_t & ActiveConnection,

        enum CursorTypeEnum CursorType,

        enum LockTypeEnum LockType,

        long Options );

其中参数ActiveConnection就是针对一个variant_t型变量的引用,它可以是一个连接串或者一个指向已打开的Connection对象的指针。

正确的_variant_t型参数会被构造,无论你传递的是一个类似"DSN=pubs;uid=sa;pwd=;"这样的字符串,或者是一个类似"(IDispatch *) pConn"的指针。

或者你还可以显式的编写"_variant_t((IDispatch *) pConn, true)"这样的代码来传递一个包含指针的_variant_t变量。这里的强制类型转换(IDispatch *)避免了可能调用IUnknown接口构造函数的模棱两可性。

虽然很少提及但特别重要的是,ADO总是一个IDispatch接口。任何被传递的被包含在Variant中的指针都必须被转换为一个IDispatch接口指针。

最后需要说明的是构造函数的第二个逻辑参数是可选择的,它的缺省值是True。这个参数将决定Variant的构造函数是否调用内嵌的AddRef()方法,并在完成ADO的方法或属性调用后是否自动调用_variant_t::Release()方法

SafeArray

SafeArray也是一种结构化的数据类型,包含了一个由其它数据类型的数据元素组成的数组。之所以称之为安全的数组是因为它包含了每一维的边界信息,并限制在边界内进行数组元素的访问。

当《ADO API Reference》中说到一个方法或属性要使用或者返回一个数组时,通常意味着是一个SafeArray数组,而非一个本地化的C/C++(www.cppentry.com)数组。

比如,Connection对象的OpenSchema方法的第二个参数需要一个由Variant值组成的数组。这些Variant值必须作为一个SafeArray数组的元素进行传递。而这个SafeArray数组本身又被作为一个Variant进行传递。

更进一步的,Find方法的第一个参数是一个指向一维SafeArray数组的Variant;AddNew方法的可选的第一与第二个参数也是一个一维的SafeArray数组;GetRows方法的返回值则是一个包含二维SafeArray数组的Variant。

缺省参数

VB允许省略方法的某些参数。例如,Recordset对象的Open方法有五个参数,但是你可以跳过中间的参数并省略之后的参数。被省略的参数会被自动创建的BSTR或Variant缺省值替代。

C/C++(www.cppentry.com)中,所有的操作数必须被明确。如果你想定义一个字符串型的缺省参数,那么就定义一个包含空字符串的_bstr_t。如果想定义一个Variant型的缺省参数,那么就定义一个值为DISP_E_PARAMNOTFOUND、类型为VT_ERROR的_variant_t。你还可以使用#import编译指示符提供的与之等价的常量vtMissing。

vtMissing的使用有三种意外情形:Connection与Command对象的Execute方法,Recordset对象的NextRecordset方法。

_RecordsetPtr Execute( _bstr_t CommandText, VARIANT * RecordsAffected,

        long Options );  // Connection

_RecordsetPtr Execute( VARIANT * RecordsAffected, VARIANT * Parameters,

        long Options );  // Command

_RecordsetPtr NextRecordset( VARIANT * RecordsAffected );  // Recordset

参数RecordsAffected与Parameters都是指向Variant的指针。Parameters是一个传入参数,指向一个包含一个或一组参数信息的Variant的地址,将决定命令执行的内容。RecordsAffected是一个传出参数,指向一个包含该方法返回时影响行的数目的Variant的地址。

Command对象的Execute方法中,如果只是没有参数的话,需要将Parameters设置为&vtMissing (推荐使用)或者一个空指针(NULL)。如果传递的是一个空指针,那么等价的vtMissing会被传递并完成操作。

在所有的方法中,通过设置RecordsAffected为空指针可以指示不需返回被影响的记录的数目。此时,这个空指针实际成为了指示该方法抛弃被影响记录数目的指示器。

因此,如下的编码是有效的:

pConnection->Execute("commandText", NULL, adCmdText);

pCommand->Execute(NULL, NULL, adCmdText);

pRecordset->NextRecordset(NULL);

错误的处理

COM中,大多数的操作总是返回一个HRESULT值说明该函数是否被成功完成。编译指示符#import为所有源方法和属性提供了封装好的代码并检查返回的HRESULT值。如果HRESULT指示失败,这些封装代码将会通过调用以HRESULT为参数的_com_issue_errorex()抛出一个COM错误。COM错误对象将在try-catch块中被捕获(出于效率的考虑,实际捕获的是一个_com_error对象的引用指针)。

记住,由ADO操作失败产生的错误才是ADO错误。由下层提供者返回的错误以Connection对象中Errors集合中的一个Error对象的形式出现。

编译指示符#import只能为在ADO.dll中声明的方法和属性提供错误处理例程。因此,你可以基于同样的错误处理机制编写自己的错误检查宏或内置函数。参见《Visual C++(www.cppentry.com)扩展》以及本文后续的示例代码。

 

内容导航

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Visual C++实现图形特技 下一篇C++实用技巧两则

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目