欢迎光临
我们一直在努力

我的ATL/ADO编程的曲折经历-.NET教程,数据库应用

建站超值云服务器,限时71元/月

我在用vc6的atl作一个组件,它内部通过ado访问access数据库。因为ado本身也是一系列组件,因此,atl项目要引入ado类型库,我是用以下语句引入的(假设windows安装在c盘):
#import “c:\program files\common files\system\ado\msado15.dll” no_namespace named_guids rename(“eof”,”adoeof”)
这是在微软的官方教材(1015 mastering com development using visual c++ 6.0)上讲的引用ado的标准方法,教材上说,这样可以使你能使用最新的ado版本。请注意,这是第一个麻烦所在。
access数据库是在access97上建立的,所以我用了jet 3.51的ole db provider,也就是说connection串是:
“provider=microsoft.jet.oledb.3.51;。。。”
这是第二个造成麻烦所在。
我的开发环境是win2k,这是第三个麻烦所在。下面请听我慢慢道来。
好了,在 win2k上调试一切正常。我一直很信任2k,因为在2k上调程序系统很稳定,另外速度好象比在98上快,最重要的是很多在98上用debug跟踪不到的错误,在2k上都能跟踪到!我信心百倍地交给用户了。用户机器是win98se,另外装了access2000。但是用户机器上报错:”create adodb.recordset failed”!当然98没有这么智能,这个错误信息是我留了个心眼儿,在程序中让它报的:
 _recordsetptr prs=null;
 if (prs.createinstance(ccombstr(“adodb.recordset”))!=s_ok)
 {
  error(“create adodb.recordset failed”);
  return e_fail;
 }
98不会不支持ado呀!我首先想到会不会是access2000的问题?但是也不应该,虽然在access2000执行界面不能修改access97的数据库结构,但是因为access2000是jet4.0驱动,它应该向下兼容地呀!通过ado是可以修改结构的,何况我并没有修改结构,我甚至连数据都没有修改!
翻箱倒柜地一通查,在mdac 2。5的帮助文件中我找到了:从ado2。1开始提供的jet4。0 ole db provider将禁用某些jet3。5x的文件,该死的微软!我不得不把连接串改成了:
“provider=microsoft.jet.oledb.4.0;。。。”
毕竟现在用户机器都升级到office2000了,用access97的人不多了。但是仍然报那个错!换到另一台装了winme的机器上安装运行,运行正常!这是怎么回事?我差点怀疑那个装98的机器系统有问题。于是我查它的注册表,hkey_classes_root\clsid下是有adodb.recordset的。在几乎绝望之际,我发现了这个:
#import msado15.dll生成的文件msado15.tlh里,_recordset的iid是
“00000556-0000-0010-8000-00aa006d2ea4”
而那个倒霉98机器的注册表的hkey_classes_root\interface下没有这个iid!我赶紧用ole view查看了98上的msado15.dll,却在里面看到了_recordset接口,所有interface,coclass应有尽有。有意思有意思!编了这么多年程序,让我长了记性:永远不要怀疑系统有问题、编译器有问题,永远要坚信是自已的程序的问题。幸亏我还算有点观察力,我发现这个98机器上的msado15.dll的_recordset接口的iid是:
“00000555-0000-0010-8000-00aa006d2ea4”
看见没有,一个是556,一个是555,它们不是一个接口!
好,仔细看看ole view为我揭示的msado15.dll:
_recordset派生于recordset20,recordset20派生于recordset15,recordset15就差不多到根上了(怪不得文件名是msado15而不是msado20或别的),它们每个的iid都不一样。我又看了看2k上的msado15.dll, _recordset派生于recordset21,recordset21派生于recordset20,下面的派生树与98上的就一样了。我又注意到,2k的msado15.dll的library节的version属性是2.5,也就是说typelib版本是2.5,而98上的是2.1。
我终于明白了,原来我开发用的ado版本与用户机器上的用户版本不一样,开发用的是ado2。5,而用户机器上的是ado2。1。ado 2。1版的recordset命名为recordset21,2。0版的recordset命名为recordset20,依此类推,而ado总是把最新版的recordset接口命名为_recordset。所以在用vc的#import时,生成的_recordsetptr是msado15.dll支持的最高版的recordset。
那么,我怎么能知道用户机器安装了哪个ado版本呢?
在msdn中没有直接的方式查找这方面的信息,或者说我无从下手。我只好用“搜索”功能。搜索“mdac”查到的主题数大大超出我的想象—有500页之多!幸亏没查“ado”,那样会更多。在看了三五个主题后,我有些头大了,微软的数据库存取技术的版本控制太混乱了!在咬牙坚持看完了不下十个主题后,终于理出了一些头绪。
首先,m$ bless me! 这个主题在搜索结果中比较靠前,使我及时了解了一些基本概念,能坚持看完后面的主题:
info: what are mdac, da sdk, odbc, ole db, ado, rds, and ado/md?
id: q190463
mdac是odbc, ole db, ado, rds四类数据库存取技术的总称。比较象样的mdac包是从版本1.5开始的。它包括odbc 3.5, ole db 1.5, ado 1.5, rds 1.5。2.0的mdac曾一度被命名为data access sdk 2.0,它包括odbc 3.51, ole db 2.0, ado 2.0, rds 2.0。以后的ado版本基本上和mdac的版本一致。除了大版本外,还有象1.5b,1.5(pdc)等小版本,但是大版本的功能是差不多一样的。
好了,我关心的是怎样确定用户机器的ado版本,然后才能知道要发布哪些文件。到用户机器上手工查看msado15.dll的typelib版本总不是个办法。这个主题好象有点用:
howto: determine the version of mdac
id: q269490
不过这要下载一个component checker的软件,或者依靠一个并不可靠的注册表项。我更想知道:给定一个用户机器的软件配置,能确定它支持的ado最小版本。
m$ bless me again! 下面的主题又比较靠前:
info: microsoft data access components (mdac) release history
id: q231943
请看ole db/ado的曲折发展进程和混乱的版本发布:
mdac 1.5在以下产品中安装了beta版:nt options pack(iis 4)/ie4/win98,正式发布是在08/01/1997的ie4,也就是说,win98或是win95+ie4可以保证ado1.5的存在。而在nt内核的操作系统中,nt4/op/iis4也最少可以用1.5。
在07/01/1998的nt4的sp4中,包含了mdac 2.0。这回nt内核超过了98内核。
在3/15/1999的ie5中,包含了mdac 2.1,我们知道win98se是与ie5绑定的。这回98内核领先了。
4/1/1999,nt上的backoffice 4.5赶了上来,支持mdac 2.1了。
2/17/2000, windows 2000来了个大一统,干脆绑定了mdac 2.5。
呵呵,我用的是msdn january 2001,后面的事情就查无出处了。我看过winme的缺省安装,是支持mdac 2.5的,98内核与nt内核走到一起了。
后来发布的还有mdac 2.6,我估计它是独立发布的。我有一台装xp的机器已经装上vs.net了,vs.net要求安装mdac 2.7。我已分不清楚2.6和2.7哪个是与xp绑定的了。不过后面你将看到,对主要用ado.recordset对象的编程者来说,mdac 2.5与2.6/2.7差别不大。
下面让我们看看ado各版本中的recordset对象都有哪些变化。
recordset15没有完善的clone和resync方法,另外很可能不支持异步方法调用(asynchronous method)。这些都在recordset20里实现了,recordset20的cancel方法支持终止异步方法调用。ado 2.0还实现了recordset的persistance,不过只支持ado专用的adtg(microsoft advanced data tablegram)格式。
recordset21增加了seek方法和index属性。另外在persistance方面还支持部分的xml格式。
从ado 2.5起,persistance得到了很大的完善。recordset对象完全支持persistance到xml格式,但是这依赖于microst xml parser,也就是msxml.dll,它从ie5开始提供。recordset对象还可以persistance到任何实现了istream接口的对象,并且ado 2.5还提供了stream对象。因此,ado 2.5的recordset可以直接persistance到iis5(windows 2000绑定)的asp response/request对象,为asp的数据存取编程提供了极大的方便。
ado 2.5以后的2.6,2.7版本对recordset的接口没有再做改动,所增强的是其他ado对象,例如ado 2.7中支持command 2.7对象。对于主要使用recordset对象的开发者来说,2.5与2.6,2.7区别不大。
好了,我班门弄斧地总结了ado的发展历程和各版本的功能,下面该讨论一下如何发布ado应用程序了。
需要说明的是,mdac包不仅随操作系统和ie发布,它也经常做为一个单独的包发布,例如在pdc(professional developer’s conference)上。它还随一些应用系统发布,如backoffice,sql server等,尤其是它也随visual studio发布。vs6中包含mdac 2.0,而vs6的sp3包含mdac 2.1。不过这些不是我们开发者考虑的主要问题.我想如果你在你的软件安装需求中写上“本软件要求您安装了mdac x.x”会使大多数用户看不懂,包括许多mcse(btw:我是mcsd,因为d在e之前,所以我有优越感)。“本软件要求您安装了vs6或者sql server”也经常会使用户感到手足无措,而“要求win98se/winnt+ie5/win2k”比较清晰明了。用户对自已用的操作系统和ie的版本是比较清楚的,这两样也是必装的,所以在确定用户机器的mdac环境时,我觉得还是主要依赖于对这两样的判断为好。
mdac包有一个安装程序mdac_typ.exe,可以把它加到你的应用程序的安装工程中去,当用户机器的ado版本比你的要求低时用它安装高版本的mdac。在vs6的安装盘中你可以找到这个程序。msdn的这个主题可以提供帮助:
redistributing mdac
但是这要在安装工程中做很多文章,而且安装包将会变得很大,另外你还可能和m$惑上官司,如果你是用d版的话。所以我更愿意把我的程序对系统的要求降到最低,换句话说,我想让我的程序使用的ado版本尽量低。怎么办呢?
首先我沮丧地想到要找一个win98或win95+ie4的机器,把它的msado15.dll复制过来#import,或者干脆在这上面开发。但是现在要找一个win98第一版或win95的机器已经很难了,而且在上面运行vs6是太别扭了。复制一个msado15.dll又很容易与开发机器上的搞混。忽然我想到vc6有一个头文件叫adoint.h,我猜它是ado interfaces的意思。在这里有ado各对象、接口的定义!我打开了adoint.h,发现它的_recordset的iid是:
“0000054f-0000-0010-8000-00aa006d2ea4”
再一查msado15.dll,这是recordset20的iid,也就是说,vc6的adoint.h提供的是ado 2.0的对象和接口。这很好理解,vs6自带的mdac2.0。再看看支持ado 2.0的最低操作系统:win98se/nt+sp4/2k/xp,这对大多数用户来说都满足的,所以按这个adoint.h的定义使用ado很理想。
如果你还想用smart pointer(_com_ptr_t)的话,如_recordsetptr,那么就要把
#import “c:\program files\common files\system\ado\msado15.dll” no_namespace named_guids rename(“eof”,”adoeof”)
换成:
#include <adoint.h>
#include <icrsint.h>

#include <comdef.h>
_com_smartptr_typedef(_connection, __uuidof(_connection));
_com_smartptr_typedef(_recordset, __uuidof(_recordset));
_com_smartptr_typedef(fields, __uuidof(fields));
_com_smartptr_typedef(field, __uuidof(field));
其中#include <icrsint.h>是可选的,它使你能用ado内部的vc支持接口iadorecordbinding来处理记录数据,避开在vc中今人生烦的对variant的处理,我比较喜欢用这个接口。
#include <comdef.h>是必须的。没有它,你会碰到一大堆编译错误,主要是“抽象类(abstract)的成员函数没有实现”之类的信息。
后面的_com_smartptr_typedef为你需要的接口指针定义smart pointer类型(_com_ptr_t的模板实现类xxxxptr)。我列出的是最常用的接口。
有一点要注意:如果你用的是vs6的sp3,那么adoint.h有可能是ado 2.1的定义(我没有vs6 sp3,不能肯定)。
这里还有一点小麻烦,用这种方法生成的smart pointer只支持接口的原生方法和属性,例如你只能用put_cursorlocation/get_cursorlocation而不能用#import为你实现的putcursorlocation/getcursorlocation,#import实现的对方法的bstr和variant参数的包装(用_bstr_t和_variant_t类)也不能用了,你必须自已处理bstr和variant,这包括对sysallocstring/sysfreestring/variantinit/variantclear/variantchangetype等的小心使用。不过如果你是用atl开发的话,atl的ccombstr和ccomvariant类可以起到_bstr_t和_variant_t同样的作用。
最后来看一下现在的大红人visual studio.net,如果你安装时选择了安装platform sdk(缺省是不安装的),vc.net的adoint.h在vs.net安装目录的vc7\platformsdk\include下。看一下这个文件,_recordset是2.5的,只有_command是派生于command25,也就是说,vc.net的adoint.h是支持ado 2.7的(ado 2.7的大多数接口与2.5相同,只有command接口是新的)。因此,虽然vc.net是vs.net中唯一能开发windows专有平台应用的工具,但是用它开发ado应用要小心,它用的是ado 2.7,如果用到了command对象,那么你的应用只能在xp上用了!
可能有人会有这样的想法,不管开发时引用的是哪个版本的ado,代码里不用_recordsetptr不就行了吗?比如用recordset20ptr,事实是这样也不行,因为#import生成的recordset20ptr代码中引用了_recordsetptr,不信你可以试试。
不揣浅陋,胡侃了这么多,请各位指正。

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 我的ATL/ADO编程的曲折经历-.NET教程,数据库应用
分享到: 更多 (0)