《ado api参考》用vb的语法描述了ado api的内容。但ado程序员却使用着不同的编程语言,比如vb,vc++,vj++。对此《ado for vc++的语法索引》提供了符合vc++语法规范的详细描述,包括功能、参数、异常处理等等。
ado基于若干的com借口实现,因此它的使用对于一个正进行com编程的程序员而言更简单。比如,几乎所有使用com的细节对于vb程序员而言都是隐藏了的,但对于vc++程序员而言却要特别注意。以下是对于c和c++程序员使用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++中,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++的语法形式:
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++中也能找到对应的类型。其中包括标准的数据类型,比如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也是一种结构化的数据类型,包含了一个由其它数据类型的数据元素组成的数组。之所以称之为安全的数组是因为它包含了每一维的边界信息,并限制在边界内进行数组元素的访问。