编程知识 购物 网址 新闻 笑话 | 软件 日历 阅读 图书馆 China
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程 CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流
站长资讯 .NET新手 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA VisualStudio ASP.NET-MVC .NET控件开发 EntityFramework WinRT-Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动 Html-Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP OracleERP DynamicsCRM K2 BPM 信息安全 企业信息 Android开发 iOS开发 WindowsPhone WindowsMobile 其他手机 敏捷开发 项目管理 软件工程 SQLServer Oracle MySQL NoSQL 其它数据库 Windows7 WindowsServer Linux
   -> vbs/VBScript -> VBS技术内幕:CreateObject函数详解 -> 正文阅读

[vbs/VBScript]VBS技术内幕:CreateObject函数详解

CreateObject函数可以说是VBS中最强大的函数,没有了它,VBS只能用来算算数学题。我们都知道CreateObject函数可以创建对象,但是很多人并不知道其中的奥秘
曾经我也不明白为什么在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跟了一下,核心的代码大概可以分成四步:


第一步调用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。


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


第三步调用IClassFactory接口的CreateInstance方法获取IUnknown接口指针,所有的COM都必须支持IUnknown接口,所以这步应该不会出错。


最后调用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
链接: http://demon.tw/reverse/vbscript-internal-createobject.html
  vbs/VBScript 最新文章
vbscript基础篇 - vbs变量定义与使用方法
vbscript基础篇 - vbs数组Array的定义与使用
VBScript 根据IE窗口的标题输出ESC
vbscript网页模拟登录效果代码
vbs能调用的系统对象小结
VBS技术内幕:CreateObject函数详解
用vbs实现删除名称中有撇号的文件夹
iPod文本分割器(VBS版)
VBScript教程 第十三课 VBScript与窗体
VBS教程:VBscript属性-Number 属性
上一篇文章      下一篇文章      查看所有文章
加:2018-05-09 23:30:53  更:2018-05-09 23:30:55 
 
360图书馆 软件开发资料 购物精选 新闻资讯 Chinese Culture 三丰软件 开发 中国文化 阅读网 日历 万年历 2019年10日历
2019-10-22 20:13:17
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  编程知识