golang 调用 MSScriptControl.ocx 脚本引擎
By S.F.
本文链接 https://www.kyfws.com/post/go-msscript/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 2 分钟阅读 - 847 个词 阅读量 0MSScriptControl.ocx 是 windows 一直内置的脚本解释器ActiveX控件,从VB时代就提供了。
前言
最近在研究一个脚本执行的模块,运行的目标环境是 Windows XP,尝试过多种实现方法,做过的尝试有:
- v8 + golang
- otto + golang
- msscript + golang
- nodejs + ffi
- delphi
- vb
- c++
如果有人感兴趣,可以分别都写出来,目前就网络还很少能找到的范例msscript + golang
的实现。
环境
首先目标是 windows xp,实施各类方案前,请确认它能否到失去支持的操作系统上运行。
1.安装虚拟机 VMWare,作为运行测试环境
2.脚本引擎必须支持调用其它的com对象,有些功能还是得基于com得调用
3.配置依赖库
-
启用 go mod
go env -w GO111MODULE=on
-
配置代理
go env -w GOPROXY=https://goproxy.io
-
安装模块
go mod download github.com/go-ole/go-ole
实现
Windows ole对象基接口为 IDispatch,ole得interface查看工具叫做 OleView32
,可以搜索下载,通常 Windows_SDK 包会内置。
获取 MSScriptControl 的 programID
此处需要用到上面提到的工具 OleView
查看ProgID
,它支持名字
或者GUID
,如图:
//创建实例
ole.CoInitialize(0)
unknown, _ := oleutil.CreateObject("MSScriptControl.ScriptControl.1")
script, _ := unknown.QueryInterface(ole.IID_IDispatch)
//ole.CoUninitialize() //此句应存在于程序末端结束时调用
CoInitialize
CoInitializeEx
是用来初始化COM运行环境的CoUninitialize
释放,必定是成对出现,请确保这一点
配置控件属性
- 将执行的脚本
Language
配置为 JScript (javascript) - 超时时间
Timeout
配置为 30* 1000 (毫秒单位,30秒)
script, _ := unknown.QueryInterface(ole.IID_IDispatch)
oleutil.PutProperty(script, "Language", "javascript")
oleutil.PutProperty(script, "Timeout", 30 * 1000)
封装运行脚本函数 Run
//Run ProcedureName As String, ParamArray Parameters() As Variant 运行一个指定的过程
func (this *MSScriptControl) Run(procedureName string, params ...interface{}) *ole.VARIANT {
defer _recover()
ret := oleutil.MustCallMethod(this.value, "Run", procedureName, params)
return ret
}
测试
输入js进行测试
abc = 2 + 2;
扩展脚本,AddObject
它作为脚本运行环境,没有任何问题,我们试试扩展对象,公开给脚本使用,就用著名的AutoItX3
来测试。
安装AutoIt3环境后,系统注册了名为AutoItX3.Control
的Com对象;将其直接公开给刚做的脚本host。
unknown, _ = oleutil.CreateObject("AutoItX3.Control")
auto, _ := unknown.QueryInterface(ole.IID_IDispatch)
ret.AddObject("auto", auto, false)
现在js可以直接使用 auto.method… 调用 AutoItX3 的接口方法了。
测试下js
auto.ToolTip("Hello");
auto.Run("notepad.exe", "c:\\windows", 1);
var _title = '[TITLE:无标题 - 记事本;CLASS:Notepad]';
if (!auto.WinActive(_title)) {
auto.WinActivate(_title);
auto.WinWaitActive(_title);
}
auto.Send('!+0');// ???????
auto.Send('aaa 123123123123123');// ???????
auto.Send("Hello, this is line 1{ENTER}");
auto.Send("This is line 2{ENTER}This is line 3");
auto.Sleep(1000);
auto.Send("!{F4}");
auto.WinWaitActive("记事本");
auto.Send("!n");
这样,js就可以方便的集成更多的库,实现更强大的功能。
golang msscriptcontrol ole 原创