跟我一起写Windows JS脚本(二):内置对象与任意COM组件

作者:yurunsun@gmail.com 新浪微博@孙雨润 新浪博客 CSDN博客日期:2012年11月2日

上一节一起搭建了Windows JS开发运行环境,并演示了一些实用的小例子,下面一起研究如何实用脚本的内置对象和任意COM组件。

1. WSH内置对象模型

WSH对象模型由一下几个对象组成:

  • WScript
  • WshArguments

    • WshNamed
    • WshUnnamed
  • WshController

    • WshRemote
  • WshNetwork

  • WshShell

    • WshShortcut
    • WshUrlShortCut
    • WshEnvironment
    • WshSpecialFolders
    • WshScriptExec

对象的详细文档可以猛击此处下载。看起来很高深的样子,其实对我们有用的只有几个对象,下面挑出有用的对象以及对象的属性方法一个个解释,其余请查阅文档。

1.1 WScript 对象

WScript是WSH根对象,不需要在调用其属性和方法之前进行实例化,始终可在任何脚本文件中使用。

  • CreateObject 方法

    WScript.CreateObject(strProgID[,strPrefix]) 
    

    strProgID就是COM技术中的术语ProgID,暂时把它理解成对象的名字。第二个位于中括号内的是可选参数,这两个参数将在后面COM组件一并解释。

    现在我们只需要知道,这个方法就是简单的创建一个名字是strProgID参数的对象。例如:

    var oIE = WScript.CreateObject("InternetExplorer.Application");     //创建IE对象
    var oWordApp = WScript.CreateObject("Word.Application");            //创建MS-Word对象
    var oWordDoc = WScript.CreateObject("Word.Document");               //创建MS-Word文档对象
    var oWMP = WScript.CreateObject("WMPlayer.OCX");                    //创建WindowsMediaPlayer播放器对象
    var oQQMusic = WScript.CreateObject("QzoneMusic.MusicPlayer");      //创建QQ控件音乐播放器对象
    var o360yun = WScript.CreateObject("CloudShell.ShellContextMenu");  //创建360云盘右键菜单对象
    

    返回值就是创建好的对象,至于这个对象定义了哪些属性和方法,我们暂时可以通过在IDE中利用提示名字猜一下,当然这不是正常途径;正确的方法还是放在下边COM组件部分解释。

  • Echo 方法

    WScript.Echo [Arg1] [,Arg2] [,Arg3] ... 
    

    将文本输出到消息框中(WScript.exe)或命令控制台窗口(CScript.exe)。

  • Sleep 方法

    Sleep(intTime)
    

    运行脚本的线程被挂起,释放它所占用的 CPU。超过指定的时间间隔后,脚本继续执行。如果运行异步操作和多过程,或者您的脚本中包括由事件触发的代码,Sleep 方法就尤其有用;事件通知稍后解释。

  • Arguments 属性如同C语言main函数传入命令行参数一样,从Arguments中可以读到脚本执行时的参数:

    objArgs = WScript.Arguments;
    for (i = 0; i < objArgs.length; i++) {
       WScript.Echo(objArgs(i));
    }
    
  • StdIn/StdOut 属性 (CScript.exe环境专用)返回一个标准输入/输出流的对象.

    var stdin = WScript.StdIn;
    var stdout = WScript.StdOut;
    while (!stdin.AtEndOfStream) {
         var str = stdin.ReadLine();
         stdout.WriteLine("Line " + (stdin.Line - 1) + ": " + str);
    }
    

1.2 WScript.WshShell 对象

提供对本地 Windows 外壳程序的访问。创建方式:

var sh = WScript.CreateObject(WScript.Shell);
  • AppActivate 方法

    激活应用程序窗口。在确定要激活哪个应用程序时,指定的标题将与正在运行的每个应用程序的标题字符串相比较。如果不存在完全匹配的标题,则将激活标题字符串以 title 开头的所有应用程序。如果还是找不到任何应用程序,则将激活标题字符串以 title 结尾的所有应用程序。如果存在多个名为 title 的应用程序实例,则将随机激活一个实例。

    var WshShell = WScript.CreateObject("WScript.Shell");
    WshShell.Run("calc");
    WScript.Sleep(100);
    WshShell.AppActivate("Calculator");
    
  • Popup 方法

    在弹出式消息框中显示文本。弹出的button、logo对应的数字可以在上边提供下载的文档中找到。

    var WshShell = WScript.CreateObject("WScript.Shell");
    var BtnCode = WshShell.Popup("Do you feel alright?", 7, "Answer This Question:", 4 + 32);
    switch(BtnCode) {
       case 6:
          WScript.Echo("Glad to hear you feel alright.");
          break;
       case 7:
          WScript.Echo("Hope you're feeling better soon.");
          break;
       case -1:
          WScript.Echo("Is there anybody out there?");
          break;
    }
    
  • Run 方法

    object.Run(strCommand, [intWindowStyle], [bWaitOnReturn]) 
    

    strCommand 表示要运行的命令行的字符串值,必须包括要传递到可执行文件的所有参数。intWindowStyle表示程序窗口外观的整数值,bWaitOnReturn 可选。布尔值,表示在继续执行脚本中的下一条语句之前,脚本是否等待执行完程序。

    var WshShell = WScript.CreateObject("WScript.Shell")
    var ret = WshShell.Run("notepad " + WScript.ScriptFullName, 1, true);
    
  • SendKeys 方法

    将一个或多个键击发送到活动窗口(模拟按键),制作外挂、自动登录的利器。各个特殊键盘的名字可以在文档中查阅。

2. “当我们CreateObject的时候,我们Create了什么

在介绍WScript.CreateObject(strProgID)时提到了传入的参数就是COM技术中的术语ProgID,而Create出来的对象就是COM组件的一个实例。先来重新回顾一下调用这个函数创建对象的例子:

var oIE = WScript.CreateObject("InternetExplorer.Application");     //创建IE对象
var oWordApp = WScript.CreateObject("Word.Application");            //创建MS-Word对象
var oWordDoc = WScript.CreateObject("Word.Document");               //创建MS-Word文档对象
var oWMP = WScript.CreateObject("WMPlayer.OCX");                    //创建WindowsMediaPlayer播放器对象
var oQQMusic = WScript.CreateObject("QzoneMusic.MusicPlayer");      //创建QQ控件音乐播放器对象
var o360yun = WScript.CreateObject("CloudShell.ShellContextMenu");  //创建360云盘右键菜单对象

相信大家好奇的是:

  • 为什么在js中根据一个字符串就能得到一个IE的对象,甚至能调用IE的方法去浏览网页、前进、后退?
  • 这个对象和真正的 C:\Program Files (x86)\Internet Explorer\iexplorer.exe有什么联系和区别?
  • 如何查看这个对象的全部方法、属性?
  • 只能调用方法访问属性吗?网页加载完成、网页加载失败404这些通知如何得到?
  • 还有哪些类似的对象,再哪里能得到所有可用对象名字及其详细信息?
  • 自己能否创建这样的对象,供js调用?

接下来会一一解释这些问题。

2.1 什么是COM组件

考虑一下几个问题:

  • QQ的新闻弹窗、YY的活动中心弹窗,都是窗口内嵌浏览器。这个浏览器是每个公司都要重新开发吗?
  • 假如QQ有一个屏蔽关键词的模块,用户安装了QQIM和QQTalk,这个模块如何共用?
  • 之前用C++开发的模块现在用C#还能可以调用么,脚本可以调用么?

第一个问题听起来与dll动态链接库有点儿类似,直观的想法是Windows开发一个浏览器dll,应用程序加载dll便可以调用其提供的方法。问题是调用者如何得知该dll提供的方法名字、参数、返回值?恐怕只能依赖文档解决;如果说第一个问题是由于不同公司交流不便,那么第二个问题(这个是虚构的)中同一家公司如何做到组件复用呢?QQTalk要把路径设置到QQ安装目录下了吗?至于第三个问题就更有些棘手了。

20年前微软为了解决这些问题,提出了对象复用的一套标准 —— COM (Component Object Model),这里的Object不同于OOP语言中的对象概念,而是建立在二进制可执行文件基础上的。这套标准是概括起来是这样的:

  • 用一种类似协议的伪代码方式,描述调用接口的名字、出入参数、返回值:

    interface IWebBrowser2 : IWebBrowserApp {
    [id(0x000001f4), helpstring("Navigates to a URL or file or pidl.")]
    HRESULT Navigate2(
                    [in] VARIANT* URL, 
                    [in, optional] VARIANT* Flags, 
                    [in, optional] VARIANT* TargetFrameName, 
                    [in, optional] VARIANT* PostData, 
                    [in, optional] VARIANT* Headers);
    [id(0x000001f5), helpstring("IOleCommandTarget::QueryStatus")]
    HRESULT QueryStatusWB(
                    [in] OLECMDID cmdID, 
                    [out, retval] OLECMDF* pcmdf);
    
  • 每个COM组件实现若干个接口,从一个接口可以转到另一个接口

  • 每个COM组件向操作系统注册自己的接口信息,以便使用者获得自己的资料。可以使用外部工具:

    C:\>regsvr32.exe dllname.dll
    
  • 每个COM组件用全球唯一的ID(CLSID)标识自己,并提供工厂创建方法创建自身。除了CLSID,还允许使用ProgID为自己命名,二者一一对应

  • 每个COM组件使用引用计数控制生存期
  • 为了支持跨语言互调(自动化技术),实现一个特定的接口IDispatch。在这个接口中,参数使用特定的VARIANT结构体作为弱类型变量,调用函数统一经过一个特定的方法Invoke再根据方法名字转发
  • 为支持反向事件通知(COM回调用户代码),实现一个特定的接口IConnectionPoint作为连接点

2.2 问题的答案

对什么是COM有一个大概的了解后,之前提出的问题会一一有答案了。

  • 为什么在js中根据一个字符串就能得到一个IE的对象,甚至能调用IE的方法去浏览网页、前进、后退?

    答:因为IE这个COM组件实现了自动化。首先创建了语言无关的二进制对象;然后实现了IDispatch接口,将不同语言的函数调用转移到Inovke中根据方法名字再次分发;然后在操作系统注册了自己的接口描述,使得IDE能够提示可供调用的方法名称

  • 这个对象和真正的 C:\Program Files (x86)\Internet Explorer\iexplorer.exe有什么联系和区别?

    答:iexplorer.exe是一个可执行程序,由多个COM组件构成。InternetExplorer.Application是其中一个

  • 如何查看这个对象的全部方法、属性?

    答:对于已经注册的COM组件,我们可以通过注册表读取键值,但更实用的是使用操作系统提供的查看工具oleview.exe。我的位于

    C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\oleview.exe
    

    目录下. 工具界面截图:

  • 只能调用方法访问属性吗?网页加载完成、网页加载失败404这些通知如何得到?

    答:对于可连接对象,我们能够做到让COM组件回调用户的代码。而WSH已经把一切做好,在js中我们按照如下方式处理。还记得 WScript.CreateObject(strProgID[,strPrefix])的第二个可选参数strPrefix。文档上是这样描述的:

    该对象的输出接口将连接到脚本文件。事件函数由该前缀和事件名称组成。如果您创建对象时未提供 strPrefix 参数,则仍可通过 ConnectObject 方法同步发生在该对象上的事件。当对象引发事件时,WSH 将调用在事件名称开头附加了 strPrefix 的方法。

    以IE组件为例,查阅oleview.exe中Internet Explore组件的DWebBrowserEvents/DWebBrowserEvents2接口或者MSDN文档我们能看到很多事件通知,我们从中选取有代表性的3个:

    [id(0x000000fb), helpstring("A new, hidden, non-navigated WebBrowser window is needed.")]
    void NewWindow2([in, out] IDispatch** ppDisp, [in, out] VARIANT_BOOL* Cancel);
    
    
    [id(0x000000fc), helpstring("Fired when the document being navigated to becomes visible and enters the navigation stack.")]
    void NavigateComplete2([in] IDispatch* pDisp, [in] VARIANT* URL);
    
    
    [id(0x00000067), helpstring("Fired when application is quiting.")]
    void Quit([in, out] VARIANT_BOOL* Cancel);
    

    绑定事件的代码如下:

    var objIE = WScript.CreateObject("InternetExplorer.Application", "objIE_");
    objIE.Visible = true;
    var pending = true;
    while (pending){
        WScript.Sleep(100);
    }
    function objIE_NewWindow2(pDisp, Cancel){
        WScript.Echo("You've tried to open a new window...");
    } 
    function objIE_NavigateComplete2(pDisp, URL){
        WScript.Echo("You just navigated to", URL);
    } 
    function objIE_DocumentComplete2(pDisp, URL){
        WScript.Echo("Document complete of", URL);
    } 
    function objIE_OnQuit(){
        WScript.Echo("You just quit ");
        pending = false;
    }
    
  • 还有哪些类似的对象,再哪里能得到所有可用对象名字及其详细信息?

    答:在oleview.exe中可以查看本机注册的所有COM

  • 自己能否创建这样的对象,供js调用?

    答:遵守COM的协定,可以非常方便的使用VC/VB/C#等语言创建二进制兼容的COM组件,供js调用


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值