欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

VBS技术内幕:CreateObject函数详解

程序员文章站 2022-06-17 22:16:06
曾经我也不明白为什么在createobject函数中传递不同的字符串就可以创建各种各样功能强大的对象。后来无意中看到umu的《[umu wsh 教程](9)createob...

曾经我也不明白为什么在createobject函数中传递不同的字符串就可以创建各种各样功能强大的对象。后来无意中看到umu的《[umu wsh 教程](9)createobject 过程》,才知道createobject函数创建的是com对象,第一个参数是com对象的progid。再后来拜读了jeff glatt的《com in plain c》,知道了如何用纯c语言编写com组件。

com(组件对象模型)是一个很复杂的概念,需要用砖头那么厚的书才能讲得清楚,而且没有c++和面向对象编程背景的话很难理解,比较经典的书有《com原理与应用》、《com技术内幕》和《com本质论》,不过貌似都绝版了。

当然,作为vbser,我们不需要去理解com的原理或者本质。简单的说,com就是别人写好的模块,我们要做的仅仅是调用它,而不必关心它的内部实现,这也是com技术的一个初衷。progid可以认为是开发人员为com对象起的一个名字,我们把com对象的名字传递给createobject函数,告诉它我们想创建这个对象,createobject函数就会返回这个对象的指针给你。

例如我可以(当然,你也可以)用vb来编写一个com组件,然后给它起个名字demon.tw,那么注册该com组件之后,就可以用createobject函数来创建了:

set blog = createobject("demon.tw")
blog.open '假设我的com对象实现了open方法

我们常用的scripting.filesystemobject、wscript.shell、adodb.stream等只不过是微软开发的系统自带的com对象的名字罢了。

那么createobject函数是如何创建对象的呢?用ollydbg跟了一下,核心的代码大概可以分成四步:

VBS技术内幕:CreateObject函数详解

第一步调用clsidfromprogidex从progid获取对应的clsid,如果找不到对应的clsid,就会报错“activex 部件不能创建对象”。

我们可以用注册表编辑器手工查找clsid。例如要获取wscript.shell的clsid,用注册表编辑器查找hkey_classes_root\wscript.shell\clsid的值即可。需要注意的是,《[umu wsh 教程](9)createobject 过程》里说:

1、createobject 函数先检查注册表 hkey_classes_root\wscript.shell 下的子键 curver 的默认值,结果为 wscript.shell.1,所以知道最新版本是 wscript.shell.1;

2、读 hkey_classes_root\wscript.shell.1,下面有一个子键 clsid,默认值为 {72c24dd5-d70a-438b-8a42-98424b88afb8};

这是错误的,createobject函数(准确的说是其内部调用的clsidfromprogidex函数)先检查注册表子键 hkey_classes_root\wscript.shell\clsid是否存在,只要子键存在,即使默认值为空或者不是类标识符,都不会再检查子键curver ,只有clsid子键不存在,才会检查子键 curver。

VBS技术内幕:CreateObject函数详解

第二步调用cogetclassobject函数获取iclassfactory接口的指针,如果获取不到,报错“activex 部件不能创建对象”或者“类不支持 automation 操作”,也可能是其他错误信息,这取决于com的实现。

VBS技术内幕:CreateObject函数详解

第三步调用iclassfactory接口的createinstance方法获取iunknown接口指针,所有的com都必须支持iunknown接口,所以这步应该不会出错。

VBS技术内幕:CreateObject函数详解

最后调用iunknown接口的queryinterface方法查询该com是非支持idispatch接口,只有支持idispatch接口的com类才能用createobject创建对象。如果获取到idispatch接口的指针,就可以给variant变量赋值了;如果不支持idispatch接口,报错“类不支持 automation 操作”,也可能是其他错误信息,取决于具体实现。

说了半天还是没有说到一个关键的问题:vbs到底能调用哪些对象?或者说,哪些字符串可以作为createobject函数的第一个参数?欲知问题答案,请听下回分解。

vbs深入createobject函数

本篇要讲的是对象的创建,属于 com 的内容,这里不可能说太多,大家可以找一些 com 的书看看,也可以看看 umu 的其他关于 com 的文章:《atl 体验》、《基于 webbrowser 的新型应用程序研究小记》、《学习 atl 的理由》、《关于 com 的几个概念问题》、《关于 com 的几个概念问题(2)》。最常见的对象有:wscript.shell、scripting.filesystemobject、scripting.dictionary 等,这里以 wscript.shell 为例。


马上来看对象的创建过程,语句 set objwsh = createobject( "wscript.shell" ):

1、createobject 函数先检查注册表 hkey_classes_root\wscript.shell 下的子键 curver 的默认值,结果为 wscript.shell.1,所以知道最新版本是 wscript.shell.1;

2、读 hkey_classes_root\wscript.shell.1,下面有一个子键 clsid,默认值为 {72c24dd5-d70a-438b-8a42-98424b88afb8};

3、找到了 hkey_classes_root\clsid\{72c24dd5-d70a-438b-8a42-98424b88afb8},子键 inprocserver32 的默认值说明服务程序是 c:\windows\system32\wshom.ocx。

4、对于脚本可以调用的 com 对象,要使用对象里的方法 typelib 是必要的,hkey_classes_root\clsid\{72c24dd5-d70a-438b-8a42-98424b88afb8} \typelib 的默认值是 {f935dc20-1cf0-11d0-adb9-00c04fd58a0b},hkey_classes_root\typelib \{f935dc20-1cf0-11d0-adb9-00c04fd58a0b}\1.0\0\win32 的默认值说明类型库是 c:\windows\system32\wshom.ocx。

支持脚本调用的 com 对象必然要实现 idispatch 接口,可以从 c:\windows\system32\wshom.ocx 的“资源 – typelib”里看出来,每个对象开头的 7 个函数都是 queryinterface、addref、release、gettypeinfocount、gettypeinfo、 getidsofnames、invoke,前 3 个是 iunknown 接口的函数。pe 文件里的 typelib 资源是 *.idl 源码文件编译后的类型库的二进制数据,可以反编译回去。不过 umu 推荐使用 exescope 查看,即使用 exescope 打开 c:\windows\system32\wshom.ocx,查看“资源 – typelib”,可以看出每个接口函数的参数和返回值定义。

vb 开发环境就是这样知道对象里有什么函数的。所以,如果我们知道一个对象名,却不知道这个对象里有什么函数,可以用上面说的方法获得。

xuejinglan 于 2007年03月31日 星期六 11:40 问 umu 这样一个问题:“系统中存在哪些对象,对象有那些函数可以调用,如何知道?”这个问题已经回答后一半了,下面回答前一半。

对象的注册信息 hkey_classes_root\clsid\{guid} 下可能会有这样的一些子键:control 说明该组件是一个 activex 控件、programmable 说明该组件支持自动化、insertable 说明该组件可以被嵌入到一个 ole 文档容器中。能找到 programmable,说明支持自动化,也就是支持 idispatch 接口,所以它可以被脚本语言使用。不过这种方式比较老了,现在已经被一个的组件类属代替,即 implemented categories 子键下面的 guid 形式的子键。比如 hkey_classes_root\clsid\{72c24dd5-d70a-438b-8a42-98424b88afb8}\implemented categories\{40fc6ed5-2438-11cf-a3db-080036f12502},看一下 hkey_classes_root\component categories\{40fc6ed5-2438-11cf-a3db-080036f12502} 下的 409 字符串值为 automation objects,也就是“自动化对象”。

查找“自动化对象”可以使用 vs 带的工具 oleview.exe,它专门用来查看 ole/com 对象的注册信息,界面如下图:

人民群众可能有点头晕了,总结一下:组件类属为 {40fc6ed5-2438-11cf-a3db-080036f12502}(automation objects) 的对象都支持被脚本调用。

接下去的创建过程不属于脚本应该考虑的范围,有兴趣学 com 的话可以研究研究,很好的一个机制,值得学习。标题: vbs技术内幕:createobject函数
作者: demon
链接:

相关标签: VBS CreateObject