COM 扩展到 AutoIt

简短介绍

什么是 COM?

COM 是 "Component Object Model"(对象组件模块)的缩写.是微软为应用程序的相互连接建立的一种公共接口.

这些接口定义为 COM 对象(Object).

使用 COM 之前, 必须知道程序与它的'接口'是如何精确地执行衔接的. 使用 COM,您现在可以“对话”指定的对象.

唯一的事情是必须了解这些对象(Objects)的名称"name"、属性'properties' 或方法'methods'.

 

什么是对象(Object)的属性或方法?

这是对象(Object)两个最基本的特征. 属性'property'保存对象包含的数据.

方法'method'是调用对象内部函数完成数据处理(执行某事件).

需要在 AutoIt 脚本中使用 COM 吗?

视情况而定. AutoIt 有许多内建函数和一个极大的 UDF 库. 你可以使用它们做出你编程的大部分.

如果你需要特别的'接口'连接到其它程序, 使用 COM 可以帮助您节省很多脚本代码行.

编写脚本必须知道, COM 对象很大程度上取决于操作系统和已安装的软件.

下面的例子已经在安装有 Microsoft Office 2000 的 Windows XP 专业版上通过测试.

AutoIt 使用 COM 的例子

要最小化所有打开的窗口. 可使用常规 AutoIt 函数,如 WinList 与 WinSetState.

但 COM 的两行代码就能得到同样的效果:

$oShell = ObjCreate("shell.application")

$oShell.MinimizeAll

提示: 此例不是最短的脚本,你可以使用 WinMinimizeAll()函数最小化所有窗口

 

第一行, 创建一个名叫 "shell.application" 的对象. 这是 Windows 的内部对象, 定义在 shell32.dll 文件中.

新对象的指针分配给变量 $oShell. 现在 $oShell 就是对象变量.

第二行, 使用 oShell 调用 " MinimizeAll" 的方法最小化所有窗口.

 

所有 Windows 系统都有一个巨大的内部对象库为不同用途简化操作.

一些应用程序,例如 Excel 或者 Word 同样也有自己的对象库.  

有时要获得你系统存在的所有对象的属性和方法是非常困难的.

搜索 Microsoft.com 或者 Google.com,可以帮助您找到一些关于您想使用的 Object 的线索.

例如, 可以在这里找到关于 "shell.application" 对象的一些信息:
http://msdn.microsoft.com/en-us/library/bb774094.aspx


要查看当前安装在计算机系统上面的所有对象,

"OLE/COM Object Viewer "(OLE/COM 对象查看器)是一个相当有用的工具

这个工具将在下面单独的章节中解释。

 

再看一个例子. 如要获取某个 HTML 网页的源代码. 可以使用内置 InetGet() 函数保存网页文件,

再用 FileRead() 来读取内容. 但以下代码也能达到相同的结果:

$oHTTP = ObjCreate("winhttp.winhttprequest.5.1")
$oHTTP.Open("GET","http://www.AutoItScript.com")
$oHTTP.Send()
$HTMLSource = $oHTTP.Responsetext

变量 $HTMLSource 现在包含了AutoItScript.com 主页完整的 HTML 源代码(即顶层 HTML 框架).

关于 "winhttp.winhttprequest" 对象的相关信息可以在这里得到:
http://msdn.microsoft.com/en-us/library/aa384106.aspx )

 

请记住这一点:对象依赖于计算机的操作系统或者已经安装的程序.

例如: winhttp.winhttprequest.5.1 对象仅存在于至少安装有 Explorer version 5 的计算机中. 

共享脚本使用 COM 对象, 要确保其它计算机上也存在这些 COM 对象

 

对象变量的表现有点不同于其他类型的 AutoIt 变量.

对象不是一个真实的值, 而是指向脚本外部某事的一个'指针'.

因此不能执行运算, 也不是的等式. 当你分配对象变量不同的值时,'指针'将会自动被释放.

例如, 给对象指定任何数字值或任何文本值强制删除对象:

$oHTTP = ObjCreate("winhttp.winhttprequest.5.1")  ; 创建对象
$oHTTP=0                                          ; 删除对象 

当脚本执行完成, 不需要删除对象变量.脚本退出时, AutoIt 会释放由脚本创建的所有活动对象.

当函数内定义一个局部对象变量,函数以返回结束时,也同样会释放对象.

 

使用 COM 进行自动化操作

一个非常受欢迎的 COM 应用是"自动化"程序编制,代替常规的 Autoit 操作函数,如:Send() 或者 WinActivate().

您可以利用那些程序内部定义的对象. 下面是"自动化"操作 Microsoft Excel 的例子:

$oExcel = ObjCreate("Excel.Application")                   ; 创建 Excel 对象
$oExcel.Visible = 1                                        ; 显示 Excel
$oExcel.WorkBooks.Add                                      ; 添加新工作表
$oExcel.ActiveWorkBook.ActiveSheet.Cells(1,1).Value="测试" ; 将 "测试" 写入第一行、第一列
sleep(4000)                                                ; 等待 4 秒看结果
$oExcel.ActiveWorkBook.Saved = 1                           ; 模拟保存工作表
$oExcel.Quit                                               ; 退出 Excel 

控制其它程序的复杂性取决于具体方案, 而不是由 AutoIt 脚本决定.

如果某事件不能如预期的运行,可能需要参考应用程序的文档资料,而不是看 AutoIt 帮助

 

专用语句

AutoIt 为 COM 应用设计了二个特别的语句:

WITH/ENDWITH 语句与 FOR/IN/NEXT 循环语句.

WITH..ENDWITH 语句

WITH/ENDWITH 语句并不增加新的功能,但它能使你的脚本更容易阅读.

例如上面使用 Excel 的范例还可以写成:

$oExcel = ObjCreate("Excel.Application")                ; 创建 Excel 对象

WITH $oExcel
    .Visible = 1                                        ; 显示 Excel
    .WorkBooks.Add                                      ; 添加新表
    .ActiveWorkBook.ActiveSheet.Cells(1,1).Value="测试" ; 将 "测试" 写入第一行、第一列
    sleep(4000)                                         ; 等待 4 秒看结果
    .ActiveWorkBook.Saved = 1                           ; 模拟保存工作表
    .Quit                                               ; 退出 Excel
ENDWITH

这个例子没有节省文本行, 但当你引用对象属性/方法的语句较长时,你可以用 WITH 语句缩短过长的语句行

FOR..IN 循环语句

The FOR...IN 循环必需使用(Collections)集合.集合(Collections)是一个特定类型的对象, 它存在多个子对象.

您可以把它们看成一个数组. (实际上, FOR..IN 语句也能在数组类型的变量上工作)

 

使用数组的 FOR..IN 循环

下面是演示 FOR..IN 循环的例子. 使用正常的 AutoIt 数组, 与 COM 无关. 只是给你说说大概原理

$String = ""               ; 一个为显示目的字符串

$aArray[0]="a"             ; 定义数组
$aArray[1]=0               ; 用几个
$aArray[2]=1.3434          ; 不同的
$aArray[3]="testestestest" ; 实例值.

FOR $Element IN $aArray    ; 从这里开始...
   $String = $String & $Element & @CRLF
NEXT

; 显示用户的结果
Msgbox(0,"For..IN 数组测试","结果: " & @CRLF & $String)

 

使用对象的 FOR..IN 循环

大部份情形下,不能使用'标准'对象方法取回(collection)集合的元素.

对于 'COM',必须'枚举'它们. 这是 FOR..IN 循环的特点.

下面的 Excel 例子在当前激活的工作表的 A1:O16 单元格范围内循环填写数字.

如果单元格内有小于 5 的数值,将替换为 0 值:

$oExcel = ObjCreate("Excel.Application") ; 创建 Excel 对象

$oExcel.Visible = 1               ; 显示 Excel
$oExcel.WorkBooks.Add             ; 添加新表

dim $arr[16][16]                  ; 这些脚本行
for $i = 0 to 15                  ; 只是创建
  for $j =  0 to 15               ; 工作表的
   $arr[$i][$j] = $i              ; 单元格
  next                            ; 数据的示例.
next

$oExcel.activesheet.range("A1:O16").value = $arr ; 将上面的数字填入工作表的("A1:O16")表格中

sleep(2000)                       ; 等待 2 秒,然后再继续

For $cell in $oExcel.ActiveSheet.Range("A1:O16")
   If $cell.Value < 5 Then
       $cell.Value = 0
   Endif
Next

$oExcel.ActiveWorkBook.Saved = 1 ; 模拟保存工作表
sleep(2000)                      ; 等待 2 秒,然后再继续
$oExcel.Quit                     ; 退出 Excel

  

COM 高级应用

下面这些是使用 AutoItCOM 必须了解的知识( COM 事件和 COM 错误处理).

如果你是 COM 程序员新手, 请先阅读一些关于 COM 的好文章.

有个关于 COM 的经典著作叫做 "Inside OLE 2",作者:Kraig Brockschmidt (微软出版).

您可以在网上找到更多关于 COM 的资源 (不是与 AutoIt 有关的):

http://msdn.microsoft.com/en-us/library/ms694363.aspx

http://www.garybeene.com/vb/tut-obj.htm (关于 Visual Basic 对象)

http://java.sun.com/docs/books/tutorial/java/concepts/     (在 Java 中使用对象)

http://msdn.microsoft.com/archive/en-us/dnarguion/html/drgui082399.asp ( C++ 事件对象)

http://www.garybeene.com/vb/tut-err.htm (Visual Basic 错误处理)

 

COM 事件

标准 COM 自动化主要使用单向通讯.

当你访问对象的属性或产生的方法时, 只要你的脚本适合它, COM 对象就能响应你的访问.

在你需要等候一些 COM 的动作发生时,这就非常便利了.

如果要知道对象某事件是否已经发生,你可以让对象在你的脚本中调用特定的 UDF, 而不必写一些循环语句.

同时你还可以在你的脚本中做其他的事.

不是所有对象都支持事件. 你必须仔细阅读对象文档资料确定对象是否支持事件.

如果支持事件, 则必须知道它支持的事件类型. AutoItCOM 只能接收'发送'类型事件.

最后你必须知道对象产生事件的名称,包括他们的自变量(如果有的话).

只有当你知道了所有这些信息,你才能开始编写使用 COM 事件的 AutoIt 脚本.

下面是一个接收因特网浏览器事件示范脚本中的一段:

$oIE=ObjCreate("InternetExplorer.Application.1")   ; 创建 Internet Explorer 对象

$EventObject=ObjEvent($oIE,"IEEvent_","DWebBrowserEvents")  ; 启动接收事件.

$oIE.url= "http://www.autoitscript.com"  ; 加载示例网页
;从这里开始,$oIE 对象在网页加载期间产生事件.
;它们的事件处理在下面显示的函数内.

;在这里写等待用户退出脚本的语句.
...(你的代码在这里)... 

$EventObject.stop            ; 告诉 IE 要停止接收事件
$EventObject=0               ; 消除对象事件
$oIE.quit                    ; 退出 IE
$oIE=0                       ; 移除内存中的 IE 信息(不是必需的)
Exit                         ; 退出主脚本


; 一些 Internet Explorer 的事件函数.
;
; 对于 IE 事件的完整动作列表, 见下面 MSDN 网页浏览器文档资料:
http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.aspx

Func IEEvent_StatusTextChange($Text)
; 在完整脚本中(见下面的链接),用一个 GUI 来显示内容.
    GUICtrlSetData ( $GUIEdit, "浏览器状态更改为: " & $Text & @CRLF, "添加" )
EndFunc

Func IEEvent_BeforeNavigate($URL, $Flags, $TargetFrameName, $PostData, $Headers, $Cancel)
; 在完整脚本中(见下面的链接),用一个 GUI 来显示内容.
; 注意: 内容与 MSDN 不同.
  GUICtrlSetData ( $GUIEdit, "导航: " & $URL & " 标记: " & $Flags & @CRLF, "添加")
EndFunc

点击这里 查看上例的完整脚本.

 

这个脚本的主干是: $EventObject=ObjEvent($oIE,"IEEvent_",...).
这个函数需要对象 $oIE, 并变更从 MYEvent_ 开始的 AutoIt 函数事件名及路径.

第三个参数是可选的. 当对象有多个事件接口,而且你不想让 AutoIt 自动选择时, 可以使用第三个参数.

导致对象连续变更路径的是 $EventObject.这个变量不需要过多注意, 除非你想要停止事件.

停止变更路径事件, 你不能仅仅已类似 $EventObject="" 的形式删除变量.

理由是那 '调用' 对象仍然正在占用这个变量的索引, 而且不会释放它,直到对象本身退出为止.

你可以借由杀死(killing) '调用'对象来解决这个问题,

也可以使用 $EventObject.Stop 告诉对象你不再需要接收任何事件.

然后你才可以 (也不是真的必需) 通过分配它一个任意数值取消事件, 类似: $EventObject=""

 

如果你知道事件 $oIE 的激活名称, 通过IE名字创建 AutoIt UDF:Event_Eventname(可选参数)实现你感兴趣的事件.
请务必确定函数中自变量的正确数目,并保证其正确的顺序规定. 否则你可能以料想不到的意外值作为结束. 

如果你不知道 (因为一些理由) 事件的名字, 你可以增加一个只有前缀的 UDF,
例如: Func IEEvent_($Eventname).

接收事件且没有 IEEvent_ Eventname UDF 存在时, 函数将调用代替变量 $Eventname 内的事件名称.

不一定要执行所有事件函数,那些不执行的将被忽略

更多使用 COM 事件函数的例子脚本在 AutoIt 3.1.1.xx beta ZIP 发布文档中,

从这里下载: http://www.autoitscript.com/autoit3/files/beta/autoit/COM/

 

AutoIt 中 COM 事件的限制

一些对象 (像 'Web 浏览器') 将自变量传递给他们的事件函数 '作为参照'.

这是为了让用户改变这些函数中的自变量,并且把它返回到对象.

然而,AutoIt 使用它自己的变量系统,对 COM 变量不是兼容的.

这意谓着所有对象值将转换成 AutoIt 变量, 因而也失去了参照原有的内存空间.

也许在不久的将来,我们可以解决这个限制 !

COM 出错处理

使用 COM 没有适当的错误处理是非常棘手的. 尤其是当你不熟悉您脚本中的对象时.

当侦测到一个COM错误时,AutoIt 脚本将立即停止执行. 这是默认设置,也是最安全的设置.

在这种情况下,你必须采取措施,以防止错误在您的脚本中发生.

如果没有方法避免 COM 差错, 你可以在脚本中安装一个"差错处理程序", 但如果这个程序被执行,表明错误已经发生.

要使脚本正常工作,这不是一个完美的解决办法,也不能捕捉非 COM 相关的脚本错误(如申明和语法错误).

使用 ObjEvent() 和一个用户自定义 COM 事件函数,把差错处理作为 COM 的正常事件是可行的.

唯一的差别是使用一个固定对象事件名:" AutoIt.Error". 见示例:

Global $g_eventerror = 0  ; 如果检查 COM 错误发生. 检查处理后必须复位.

$oMyError = ObjEvent("AutoIt.Error","MyErrFunc") ; 建立客户错误处理程序

; 这里执行一个预设故障(对象不存在)
$oIE = ObjCreate("InternetExplorer.Application")
$oIE.visible = 1
$oIE.bogus
if $g_eventerror then Msgbox(0,"","前一行有一个错误.")

Exit


; 这是我(编者)自定义的错误处理程序
Func MyErrFunc()
   $HexNumber=hex($oMyError.number,8)
   Msgbox(0,"","截获一个 COM 错误 !" & @CRLF & _
                "错误代码: " & $HexNumber & @CRLF & _
                "错误描述: " & $oMyError.windescription )

   $g_eventerror = 1 ; 函数返回
Endfunc

 

有一个特别有关错误事件处理程序的情况, 即它返回的对象. 这是 AutoIt 错误对象,其中包含了一些有用的属性和方法. 它的执行部分是基于VB(脚本)中的“Err”对象:

AutoIt 错误对象的属性:

.number   窗口 HRESULT 的值来自 COM 调用
.windescription FormatWinError() 错误文本来自 .number
.source  对象产生错误的名称 (内容来自 ExcepInfo.source)
.description 源对象错误描述 (内容来自 ExcepInfo.description)
.helpfile 源对象 helpfile 错误 (内容来自 ExcepInfo.helpfile)
.helpcontext 源对象 helpfile 环境 ID 编号 (内容来自 ExcepInfo.helpcontext)
.lastdllerror GetLastError() 的返回数
.scriptline 发生错误的脚本行

AutoIt 错误对象的处理方法:

.raise 引发错误的情况下,由用户启动
.clear  清除错误对象的内容 (即设置为 0 值, 字符串设置为 "")

 

编写 UDF 程序的一个注意

在 AutoIt 脚本中, 您最多只能激活一个错误事件处理程序. 如果你正在编写包含 COM 函数的 UDF, 可以检查用户是否安装有错误处理程序.

您可以这样检查:

$sFuncName = ObjEvent("AutoIt.Error")
if $sFuncName <> "" then Msgbox (0,"提示","用户已经安装了错误处理函数: " & $sFuncName)

如果没有错误处理程序是激活的,可以暂时安装自己的 UDF 调用.

但是, 在没有释放被指定的变量时,你不能停止现有的错误处理程序. 如果脚本作者已安装 COM 错误处理程序,

他的职责是使用一个适当的函数找出由 UDF 产生的 COM 错误.

 

OLE/COM 对象查看器

"OLE/COM Object Viewer"(OLE/COM 对象查看器)查看你系统上安装的所有 COM 对象时,是一个非常便利的工具.

它是 Windows 2000 资源套件的一部份,并且能从下面地址免费下载: http://www.microsoft.com/downloads/details.aspx?familyid=5233b70d-d9b2-4cb5-aeb6-45664be858b6&displaylang=en

这个程序的安装有有点儿尴尬.它不为你产生任何启动菜单图标.

执行文件 oleview.exe 安装在 C:\Program Files\Resource 套件目录中.(默认安装).

当运行 oleview.exe 时,一些系统将会提示找不到 iviewers.dll 文件. 这是个必须的文件,

奇怪的是不包含在最新安装之中.你可以从下面地址获得一个 oleview.exe 较旧版本: http://download.microsoft.com/download/2/f/1/2f15a59b-6cd7-467b-8ff2-f162c3932235/ovi386.exe

它将默认安装到 C:\MSTOOLS\BIN 目录.你只需将文件 iviewer.dll 复制到 oleview.exe 所在目录,

然后使用命令行注册DLL: regsvr32 iviewers.dll.

中文版 autoit3 将 oleview.exe 文件安装在:E:\autoit3\Extras\OLEview 文件夹中(默认安装),同时已存在必须的 iviewers.dll 文件.

 

让我们用 Oleviewer 做一个例子. 运行 oleview.exe 依次展开:

Object Classes->Grouped by Component Category->Control->Microsoft Web Browser.

 

在左侧栏中你可以看到为对象定义的所有 COM 接口. 我们稍后讨论这些.

仔细看看右栏. 它包含在 AutoIt 脚本中使用这个对象的许多信息. 最重要的是 "VersionIndependentProgID".

这是一个在 ObjCreate, ObjGet 或 ObjEvent 函数中使用的名字. 此外它还包含对象的目录和文件名. 这可能是 EXE, DLL 或 OCX 文件.

InProcServer32 意味着您的脚本与对象运行在同一线程(进程).

当您见到 LocalServer32, 表示对象作为单独的进程运行. 该对象还必须包含一个类型库 ("TypeLib=" 之后的行), 否则无法使用在 AutoIt 脚本中.

 

左侧列中的接口用于与对象交互的不同方法. 有些用来做储存 (IStorage, IPersist), 其它的嵌入 GUI (IOleObject, IOleControl).

AutoIt 使用 IDispatch 作为自动化接口. 这个接口'暴露' 该对象支持脚本的全部方法和属性.

如果它不存在,则无法在一个 AutoIt 脚本中使用对象.

让我们来看看在这个界面. 右键单击 IDispatch 名称并在右键菜单选择 "View...". 然后单击"View TypeInfo..." 按钮. 

(注意: 如果这个按钮是灰色的,表示你没有注册 iviewers.dll 文件,或对象没有这个类型库)

"ITypeInfo Viewer" 窗口仅显示该对象提供的信息. 如果开发者没有包括帮助文件,你只能看到方法/属性的名称而没有其他信息.

"Microsoft Web Browser" 类型库内容相当广泛. 在左边列中点击一个项目,该项目的描述将会在右边显示.

有时你必须浏览 "Inherited Interfaces" 为对象检索更多的方法.

描述方法/属性的语法是 C/C++ 样式. 

属性描述为 "HRESULT Resizable([in] VARIANT_BOOL pbOffline)", 必须在 AutoIt 重写为:  $Resizable=$Object.Resizable 

($Object 保存对象创建的 ObjCreate 或 ObjGet).

常用术语

以下这些术语通常与 COM 一起混和使用, 但是有不同的意义: 

OOP = 面向对象编程. 把可重复使用的软件组件构建成模块并称为对象.

DDE = 动态数据交换. 可以说这是 COM 的前身. 在不同的应用程序之间使用 IPC 传递命令信息.

OLE = 对象链接和嵌入. 第一个版本是 DDE 的扩充版本. 从一个程序 '嵌套' 数据到另外一个程序. 目前的 OLE 建立在 COM 之上,并且成为 ActiveX 的一部分

Automation = 操作另一个应用程序对象的方法. 用在 OLE, ActiveX 与 COM 中.

ActiveX = OLE 的下一代自动操作装置, 起先主要用于开发网络应用之间的接口(尤其是 web 浏览器). 建立在 COM 之上.

DCOM= 分布式 COM. 一个略有修改的 COM, 它能够沟通不同的物理计算机.

.NET (dot Net)= 不是一个真正的软件, 但微软的 '概念' 认为,这是互连网“一切动作”通过的软件. "dot Net" 主要用于网络服务.

COMmunist = 这个不支持 COM, 但有什么人信奉 communism (一种理论认为,普通老百姓应该拥有自己所有的财产). ( 译注:此处牛头不对马嘴!或是幽默,或是寻开心....总之不知为何?最后那个词就不翻译了!).

 

provider with jb51.net (unicode)