| 在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 {
_RecordsetPtr pRs("ADODB.Recordset");
_ConnectionPtr pCn("ADODB.Connection");
_variant_t vtTableName("authors"),
vtCriteria;
long ix[1];
SAFEARRAY *pSa = NULL;
pCn->Open("DSN=pubs;User ID=sa;pwd=;Provider=MSDASQL;", "", "",
adConnectUnspecified);
// Note 2, Note 3
pSa = SafeArrayCreateVector(VT_VARIANT, 1, 4);
if (!pSa) _com_issue_error(E_OUTOFMEMORY);
// 为第三个元素赋值TABLE_NAME(索引值2).
ix[0] = 2;
TESTHR(SafeArrayPutElement(pSa, ix, &vtTableName));
// 由于Variant没有SafeArray的构造函数,所以手工设置Variant的数据类型和值。
vtCriteria.vt = VT_ARRAY | VT_VARIANT;
vtCriteria.parray = pSa;
pRs = pCn->OpenSchema(adSchemaColumns, vtCriteria, vtMissing);
long limit = pRs->GetFields()->Count;
for (long x = 0; x < limit; x++)
printf("%d: %s\n", x+1,
((char*) pRs->GetFields()->Item[x]->Name));
// Note 4
pRs->Close();
pCn->Close();
}
catch (_com_error &e)
{
printf("Error:\n");
printf("Code = %08lx\n", e.Error());
printf("Code meaning = %s\n", (char*) e.ErrorMessage());
printf("Source = %s\n", (char*) e.Source());
printf("Description = %s\n", (char*) e.Description());
}
CoUninitialize();
}
使用属性的Get/Put/PutRef
在VB中,属性的名称并未被检验,无论它是被读取、被赋值,或者赋予一个引用。
Public Sub GetPutPutRef
Dim rs As New ADODB.Recordset
Dim cn As New ADODB.Connection
Dim sz as Integer
cn.Open "Provider=sqloledb;Data Source=yourserver;" & _
"Initial Catalog=pubs;User Id=sa;Password=;"
rs.PageSize = 10
sz = rs.PageSize
rs.ActiveConnection = cn
rs.Open "authors",,adOpenStatic
' ...
rs.Close
cn.Close
End Sub
以下是VC++关于Get/Put/PutRefProperty的演示
1.这个例子演示了省略字符串参数的两种形式:一种是采用常量strMissing,另一种则是由编译器自动生成一个临时的存在于Open方法使用期间的_bstr_t。
2.因为操作数已经是(IDispatch *)的指针,所以没有必要将rs->PutRefActiveConnection(cn)的操作数再进行类型转换。
#import "c:\Program Files\Common Files\System\ADO\msado15.dll"
no_namespace rename("EOF", "EndOfFile")
#include <stdio.h>
void main(void)
{ CoInitialize(NULL);
try
{ _ConnectionPtr cn("ADODB.Connection");
_RecordsetPtr rs("ADODB.Recordset");
_bstr_t strMissing(L"");
long oldPgSz = 0,
newPgSz = 5;
// Note 1
cn->Open("Provider=sqloledb;Data Source=a-tima10;"
"Initial Catalog=pubs;User Id=sa;Password=;",
strMissing, "",
adConnectUnspecified);
oldPgSz = rs->GetPageSize();
// -or-
oldPgSz = rs->PageSize;
rs->PutPageSize(newPgSz);
// -or-
rs->PageSize = newPgSz;
// Note 2
rs->PutRefActiveConnection( cn );
rs->Open("authors", vtMissing, adOpenStatic, adLockReadOnly,
adCmdTable);
printf("Original pagesize = %d, new pagesize = %d\n", oldPgSz,
rs->GetPageSize());
rs->Close();
cn->Close();
}
catch (_com_error &e)
{
printf("Description = %s\n", (char*) e.Description());
}
::CoUninitialize();
}
使用GetItem(x)和Item[x]
下面是VB中关于Item()的标准与交互语法的演示。
Public Sub GetItemItem
Dim rs As New ADODB.Recordset
Dim name as String
rs = rs.Open "authors", "DSN=pubs;", adOpenDynamic, _
adLockBatchOptimistic, adTable
name = rs(0)
' -or-
name = rs.Fields.Item(0)
rs(0) = "Test"
rs.UpdateBatch
' Restore name
rs(0) = name
rs.UpdateBatch
rs.Close
End Sub
以下则是VC++关于Item的演示
当访问collection中的Item时,索引值2必须被转换为long类型以确保正确的构造函数被调用。
#import "c:\Program Files\Common Files\System\ADO\msado15.dll"
no_namespace rename("EOF", "EndOfFile")
#include <stdio.h>
void main(void)
{
CoInitialize(NULL);
try {
_RecordsetPtr rs("ADODB.Recordset");
_variant_t vtFirstName;
rs->Open("authors",
"Provider=sqloledb;Data Source=a-tima10;"
"Initial Catalog=pubs;User Id=sa;Password=;",
adOpenStatic, adLockOptimistic, adCmdTable);
rs->MoveFirst();
// Note 1.取得一个字段的名称
vtFirstName = rs->Fields->GetItem((long)2)->GetValue();
// -or-
vtFirstName = rs->Fields->Item[(long)2]->Value;
printf( "First name = '%s'\n", (char*) ((_bstr_t) vtFirstName));
rs->Fields->GetItem((long)2)->Value = L"TEST";
rs->Update(vtMissing, vtMissing);
// 恢复原名称
rs->Fields->GetItem((long)2)->PutValue(vtFirstName);
// -or-
rs->Fields->GetItem((long)2)->Value = vtFirstName;
rs->Update(vtMissing, vtMissing);
rs->Close();
}
catch (_com_error &e)
{
printf("Description = '%s'\n", (char*) e.Description());
}
::CoUninitialize();
}
|