| IANT * 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++扩展》以及本文后续的示例代码。 在VC++与VB中编码时的约定 下面是ADO文档中关于如何使用VB和VC++编写代码的一个概览。 声明一个ADO对象 在VB中,一个ADO对象变量(此处以Recordset对象为例)如下声明: Dim rst As ADODB.Recordset 子句"ADODB.Recordset"是在注册表中登记的Recordset对象的ProgID。而一个Record对象的实例如下声明: Dim rst As New ADODB.Recordset 或者: Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset 而在VC++中,#import为所有的ADO对象生成了智能的指针类型。比如一个指向_Recordset对象的指针变量的数据类型为_RecordsetPtr,并如下声明: _RecordsetPtr rs; 而一个_Recordset对象的实例则如下声明: _RecordsetPtr rs("ADODB.Recordset"); 或者: _RecordsetPtr rs; rs.CreateInstance("ADODB.Recordset"); 或者: _RecordsetPtr rs; rs.CreateInstance(__uuidof(_Recordset)); 当CreateInstance方法被成功调用后,该变量可被如此使用:rs->Open(...); 注意,如果变量是一个类的实例则用"."操作符,若是一个指向实例的指针则应使用"->"操作符。 一个变量能通过两种方式被使用。因为"->"操作符被重载,允许一个对象实例类似一个接口指针那样被使用;"->"操作符返回该指针;而由这个返回的指针访问_Recordset对象的成员。 编写省略String参数的代码 当你需要利用VB编写省略String参数的代码时,只需简单的略掉该操作数即可。但在VC++中,你必须指定该操作数为一个包含空字符串的_bstr_t变量:_bstr_t strMissing(L""); 编写省略Variant参数的代码 当你需要利用VB编写省略Variant参数的代码时,只需简单的略掉该操作数即可。但在VC++中,你必须指定所有的操作数。编写省略Variant参数的代码只需将该Variant设为专门的值,可以定义一个值为DISP_E_PARAMNOTFOUND、类型为VT_ERROR的_variant_t。还可以使用#import编译指示符提供的与之等价的常量vtMissing。 _variant_t vtMissingYours(DISP_E_PARAMNOTFOUND, VT_ERROR); 或者: ...vtMissing...; 声明一个Variant 在VB中,一个Variant如下被声明: Dim VariableName As Variant 在VC++中,定义一个_variant_t型的变量即可。主要有以下几种形式。注意:这些声明只是你在变成时刻采用的一个粗略的思路。 _variant_t VariableName(value); _variant_t VariableName((data type cast) value); _variant_t VariableName(value, VT_DATATYPE); _variant_t VariableName(interface * value, bool fAddRef = true); 使用Variants数组 在VB中,利用Dim语句可以进行Variant数组的编程,并可以使用Array的函数。见如下示例: Public Sub ArrayOfVariants Dim cn As ADODB.Connection Dim rs As ADODB.Recordset Dim fld As ADODB.Field cn.Open "DSN=pubs", "sa", "" rs = cn.OpenSchema(adSchemaColumns, _ Array(Empty, Empty, "authors", Empty)) For Each fld in rs.Fields Debug.Print "Name = "; fld.Name Next fld rs.Close cn.Close End Sub 以下的代码演示了如何通过一个_variant_t使用一个SafeArray数组。注意注释对应了编码的步骤。 1.再一次的,TESTHR()内置函数被定义以利用预存的错误处理机制。 2.如果你只需要一个一维数组,你可以使用SafeArrayCreateVector,而非SAFEARRAYBOUND声明与SafeArrayCreate函数。下面的代码使用了SafeArrayCreate: SAFEARRAYBOUND sabound[1]; sabound[0].lLbound = 0; sabound[0].cElements = 4; pSa = SafeArrayCreate(VT_VARIANT, 1, sabound); 3.枚举常量adSchemaColumns定义的模式,决定了与TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME和COLUMN_NAME四列相联系。为此,一个有四个Variant元素的数组被创建。而对应于第三列TABLE_NAME的值被设置。 由若干列组成的返回的Recordset只是对应的所有列的一个子集,并且每一行的值保持了一一对应。 4.熟悉SafeArrays的人也许会对退出前没有调用SafeArrayDestroy()感到惊奇。实际上,在这种情况下调用SafeArrayDestroy()会导致一个运行时的异常发生。这是因为vtCriteria的析构函数会在_variant_t超出使用范围时调用VariantClear(),从而释放SafeArray。只调用SafeArrayDestroy,而没有手动清除_variant_t,将会导致析构函数试图去清除一个无效的SafeArray指针。如果要调用SafeArrayDestroy(),那么代码应该象这样: TESTHR(SafeArrayDestroy(pSa)); vtCriteria.vt = VT_EMPTY; vtCriteria.parray = NULL; 实际更像是让_variant_t管理SafeArray。 完整的代码如下: #import "c:\Program Files\Common Files\System\ADO\msado15.dll" \ no_namespace rename("EOF", "EndOfFile") #include <stdio.h> // Note 1 inline void TESTHR( HRESULT _hr ) { if FAILED(_hr) _com_issue_error(_hr); } void main(void) { CoInitialize(NULL); try {   上一页 [1] [2] [3] [4] [5] [6] 下一页 |