目前位置: VCer资源中心 >>> VCer文章 >>> 数据库

[本帖已阅读2514次 分值85 回复0次] 张贴资源 发回信箱 控制面板

snoopy每日一译-完美的ADO[2](上)

提供者:ycr40 张贴时间:2004-04-29 21:19:11.0 出处:vcer.net 作者:不祥

snoopy每日一译-完美的ADO[2](上)(2004-04-29 21:19:11.0)


snoopy


 
级别: VCer排长
头衔: VCer会员

经验: 1285
作品: 28
分会: 华南分会
注册: 2004-04-15 09:22:35.0
登录: 2004-05-18 08:45:59.0

本文告诉你怎样使ADO在你未来的应用中更简单。但是,首先,先向你展示使用ADO的另外一些细节(在你的ATL COM对象中或在你的应用程序中)。例子中,我会向你展示如何在ATL对象中使用ADO。我们使用ATL建立business层对象的所有数据IO和规则。

这样不但允许我们在特定的应用中使用这些规则和数据,而且另外一些“相关”的应用程序可以使用它们。以下是本文接触到的内容:

1、建立一个ATL对象。

2、在ATL对象中加入ADO。

3、在接口中加入方法和属性。

4、BSTR(_bstr_t), VARIANT(_variant_t), 和 SAFEARRAY。

5、使用Connection对象连接/关闭连接,从SQL建立记录集,使用Command对象。

6、使用Command对象执行存储程序。

7、将记录集转换称符号分割字符串,并传送给客户程序。

8、封装访问ADO的business逻辑应用。

9、展示VC++和VB如何使用COM对象的方法和属性。

完美的ADO II

by:Bob Place 1999.6.27

from:codeGuru

翻译:snoopy

一年多以前,我写了通用的Recordset。这是一个简单的包封了CDaoRecordset的类,令使用动态绑定大大简单化。然后,ADO来了,它缺省地使用动态绑定,跟DAO和通用的Recordset说了GOODBYE。为了帮助别人认识到使用ADO是多么容易,也是因为缺少ADO和VC的文档,我写了"完美的ADO"。现在,我想更进一步。本文告诉你怎样使ADO在你未来的应用中更简单。但是,首先,先向你展示使用ADO的另外一些细节(在你的ATL COM对象中或在你的应用程序中)。例子中,我会向你展示如何在ATL对象中使用ADO。我们使用ATL建立business层对象的所有数据IO和规则。

这样不但允许我们在特定的应用中使用这些规则和数据,而且另外一些“相关”的应用程序可以使用它们。以下是本文接触到的内容:

1、建立一个ATL对象。

2、在ATL对象中加入ADO。

3、在接口中加入方法和属性。

4、BSTR(_bstr_t), VARIANT(_variant_t), 和 SAFEARRAY。

5、使用Connection对象连接/关闭连接,从SQL建立记录集,使用Command对象。

6、使用Command对象执行存储程序。

7、将记录集转换称符号分割字符串,并传送给客户程序。

8、封装访问ADO的business逻辑应用。

9、展示VC++和VB如何使用COM对象的方法和属性。

正如你可判断的,这是一篇很长的文章。我不能覆盖所有的东西,虽然我很想这样。因此如果你想得到更详细的细节,我会向你介绍别的参考文章。

使用ATL建立通用ADO COM对象:

我们要做的第一件事是建立一个ATL对象。使用向导很容易建立一个ATL。我们将通用ADO作为一个EXE,但是你可以选择DLL。选择EXE的优点是它不会扰乱你的客户端应用程序,因为他们在不同的进程空间。但是你认为你的客户端应用程序不会被扰乱,可以选择DLL。如果你是一个像我

这样的人,我建议选择EXE。

1、打开ATL COM向导,命名未MyADO(或者另外你喜欢的名字),按OK。

2、选择服务器类型,EXE或DLL。完成。

这样你就建立了一个COM对象(虽然一点用也没有)。现在我们必须给它加一个接口。

1、在Insert菜单中,选择New ATL Object。

2、双击Simple Object图标。然后会弹出一个对话框。

3、输入名字为ADO。

4、在Attributes中,看看里面的内容,只须装着明白点点头,但千万不要修改任何东西。

5、按OK。

好,你已经建立了含有CADO类和IADO接口的MyADO COM对象。CADAO类是一个c++类,因此你可以像你所熟悉的其它一些类一样使用它。IADO只是你的COM客户端可以看到的东西而已。当你建立了一个MyADO对象,你可以使用所有加到这个接口的内容。后面我们会看得更清楚,现在重要的只是记住接口有两个重要的部分:它们是属性和方法。使用属性和方法的例子:

Property

(VB)

MyADOObject.SomeProperty = 10

(VC)

MyADOObject->put_SomeProperty(10);

Method

(VB)

Counter = MyADOObjcet.GetInt("SELECT COUNT(*) FROM some_table")

(VC)

MyADOObjcet->GetInt("SELECT COUNT(*) FROM some_table",&Counter)

在使用COM方法时,VB和VC的一个不同的地方是:用VC访问的时候,没有缺省的参数,就是说,如果方法有5个参数,那么你必须提供5个参数;

而使用VB可以跳过你不需要的参数。在我的COM对象中,我常有一个全局的变量:

VARIANT m_vNull;

然后,在构造器中初始化:

m_vNull.vt=VT_NULL;

m_vNull.scode = DISP_E_PARAMNOTFOUND;

这个变量可以在你想使用缺省参数的时候使用。

我们有了一个简单的含有一个接口的COM对象。现在,我们需要加入ADO。和在应用程序中使用ADO一样,你必须在stdfx.h中加入导入ADO的代码

。因为我将ADO的路径在包含文件中(TOOLS->Options->Directories Tab),因此我们只需加入

#import "msado15.dll" no_namespace rename("EOF","adoEOF")

如果你没有将ADO的路径包含进去,你必须将上面的语句该成ADO文件的完整路径。具体可参照“完美的ADO”。

我们要做的第一件事情是建立_ConnectionPtr,_CommandPtr, 和 _RecordsetPtr的一个全局的实例:

1、右击CADO;

2、选择Add Member Variable;

3、变量类型是_ConnectionPtr,变量名是m_Connection。

4、同样的方法:_CommandPtr, m_Command 和 _RecordsetPtr , m_Recordset。

因为我们的例子一次只连接一个数据库,因此你可以使用一个全局的Connection和一个全局的Command。记住:Connection对象用来连接数据库

;Command对象用来执行存储程序。通常每个COM session有一个Connection、Command、Recordset就够了。也不是说你不可以加入多一些。但

是我们发现简单最完美。

现在我们在构造器中初始化它们:

m_Connection.Createinstance(__uuidof(Connection));

m_Command.Createinstance(__uuidof(Command));

m_Recordset.CreateInstance(__uuidof(Recordset));

我们也必须在释构器中释放它们:

try

{

 if(m_Connection->State == adOpen)

 {

  // the connection is still open so we need to close it

  m_Connection->Close();

 }

 if(m_Recordset->State == adOpen)

 {

  // the connection is still open so we need to close it

  m_Recordset->Close();

 }

 m_Connection = NULL;

 m_Command = NULL;

 m_Recordset = NULL;

}

catch(_com_error &e){} // error handling here

catch(...){}// all other exceptions here

注意到我们在将它们赋值为NULL之前,检查确认connection和recordset没有打开。我们要在COM服务器中加入的东西就这么多了。现在我们要

决定我们的COM对象能做点什么了。但首先,让我们看看SAFEARRAYS, VARIANTS, 和 BSTRS。我们必须经常使用它们,因此我们必须理解它们是

如何工作的。(你可能也想到标准string和strstream模板)。因为我们喜欢简单,并且我们的COM服务器的目的是可以被任何语言的客户端使

用。因此我们只使用SAFEARRAYS, VARIANTS, 和 BSTRS,这样我们的生活就会更简单。

BSTR(和封装了的_bstr_t)是一个字符串和一个包含字符串大小的数。使用它们很简单,但你必须为它们分配和释放内存。有很多种方法分配

和释放内存,最常用的一种方法是:使用::SysAllocString和::SysFreeString。我喜欢使用_bstr_t,使用它你可以完全忽略分配和释放内存

,因为它为你做了。

#include <comdef.h> //_bstr_t 所在的地方

_bstr_t BstrHolder("this is a BSTR");

你想要char *,只需简单地使用类型转换即可:

char *holder = (char*)BstrHolder;

我们使用它来和COM对象传递信息。你可以将它转换成你想要的类型:char *,CString等。我们将只使用它来和COM对象传递信息(字符串信息

)。

让我们也考虑一下BSTR和内存分配和释放的问题。应该是谁分配内存,又是谁负责释放内存呢?规则相当简单:

1、如果参数是[in],那么客户端必须分配和释放内存。COM服务器不能改变它。

2、如果参数是[out],那么客户端必须分配内存,COM服务器可以从新分配,但客户端负责释放。

3、如果是COM内建变量,COM对象负责分配和释放。

VARIANT(和它的封装类_variant_t)是大量的类型的联合。使用_variant_t很容易转换类型。VARIANT被广泛使用在VB、和scripting语言中。

一旦你习惯了它,它在c++中也很有用。在和COM通讯时,当使用的不是简单的数据类型,或我们希望返回的数据可能是几个不同的东西(例如

它可能是一个字符串或一个错误号码,可以检查VARIANT的vt属性以得到数据类型)。让我们看看如何用_variant_t建立一个VARIANT。

#include <comdef.h> // this is where the _bstr_t is

_bstr_t BstrHolder("this is a Bstr");

_variant_t Holder(BStrHolder)

或者:

_variant_t Holder;

Holder = BstrHolder;

// 然后获取char *

char * cHolder = (char*)_bstr_t(Holder);

基本上我们先建立一个_bstr_t,然后将它送入_variant_t,然后使用类型转换回_bstr_t。

(未完待续)

注:转载文章需注明来源:VCer.net 文章地址:http://vcer.net/2005.html

  如果你觉得VCer.net不错,而且你愿意为VCer.net捐赠一元钱,那么点击后面的捐赠按钮吧:) vcer.net捐赠

[回复该贴] [加入个人书签]
[连载系列]

[1] snoopy每日一译-完美的ADO
[2] snoopy每日一译-完美的ADO[2](上)
[3] snoopy每日一译-完美的ADO[2](中)
[4] snoopy每日一译-完美的ADO[2](下)

[投票结果]

A: 评分 10 0% (0 票)
B: 评分 5 100% (1 票)
C: 评分 0 0% (0 票)
D: 评分 -5 0% (0 票)
E: 评分 -10 0% (0 票)