批处理之家's Archiver

CrLf 发表于 2015-1-30 06:05

bat、vbs、js 原生混编

[i=s] 本帖最后由 CrLf 于 2015-8-23 02:22 编辑 [/i]

发现 mshta 会把 file:// 协议指向的文件当作 html 来解析(注:IUnknown 与 happyxxdhaha 提醒此处必需使用绝对路径,否则不会执行),心里顿时有一万只草泥马奔过,原来如此简单的答案就在身边,却错过了四年
基本框架:[code]<!-- : www.bathome.net
@echo off
echo I'm Batch!
mshta "file://%~f0"
pause&exit

使用注释标签囊括批处理部分,条件是批处理部分不能出现注释标签的结束符
-->

<script language=vbs>
Msgbox "I'm VBScript!"
</script>

<script>
alert("I'm JavaScript!")
</script>

<script>close()</script>[/code]事实上,file:// 协议名可以省略,而且如果不需要理会界面的话,完全可以不用注释标签:[code]@echo off
echo I'm Batch!
mshta "%~f0" <nul
pause&exit

批处理部分之后要加上一串 >,数量要比前文出现的 < 更多,mshta 才能区分哪些是标签
而且前文出现从文件获取重定向输入的时候,建议加上双引号,例如 <"script"
>>>>>>>>>>>>>>

<script language=vbs>
Msgbox "I'm VBScript!"
</script>

<script>
alert("I'm JavaScript!")
</script>

<script>close()</script>[/code]另一用 goto 的种写法可能更直观一点:[code]@goto :bat

<script language=vbs>
Msgbox "I'm VBScript!"
</script>

<script>
alert("I'm JavaScript!")
</script>

<script>close()</script>

:bat
@echo off
echo I'm Batch!
mshta "%~f0" <nul
pause&exit[/code]要注意的是,这里的宿主是 mshta,所以不支持 WSH 宿主的方法和属性(部分属性或方法的替代方案详见后文)
但是!mshta 有嘛不好!
原生支持 setTimeout
原生支持 iframe
原生支持 dom
原生支持 javascript、vbscript 无障碍交互
原生支持 Ajax
原生支持加载外部脚本
原生支持在窗口中选择文件
原生支持复杂的页面交互
...
有这么多便利,那还计较什么呢?
[color=White]首发于批处理之家[/color]
------------------------------------------------------------------------------------------------------------
关于 mshta 宿主的一些知识,参考: [url]https://msdn.microsoft.com/en-us/library/ms536495(VS.85).aspx[/url]
感谢 xiaopo 扫盲,才知道联盟早已出现过 mshta 方案的雏形:[url]http://cndos.fam.cx/forum/viewthread.php?tid=39655[/url],回头上镜像站搜下,看看有没有进一步的发展

CrLf 发表于 2015-1-30 06:13

[i=s] 本帖最后由 CrLf 于 2015-8-26 20:52 编辑 [/i]

好了,我们还要消灭两个障碍~

我们知道批处理可以用 %1~%9 获取切分好的命令行参数,mshta 则没有直接的办法来获取
另一方面,mshta 是个 GUI 宿主,如果不能较好地和控制台交互,调用 mshta 将束手束脚

好在,这些都是可以解决的
-----------------------------------------------------
[size=5][b]1、命令行参数的实现[/b][/size]
获取 mshta 的启动参数先要创建一个 HTA:APPLICATION 标签,并设置一个 id,例如:[quote]<HTA:APPLICATION id=mshta></HTA>[/quote]
这里以 id=mshta 为例,可以用 mshta.commandLine 获取未切分的命令行参数
然后就可以按 windows 的规则来解析,例如:[code]<script>var argv = getopts(mshta.commandLine)
for(var i=0;i<argv.length;i++)alert(argv[i])

function getopts(strArg){
        var re = /[^"\s,;=]*"([^"]*("[^"\s,;=]*")*)*("[^"\s,;=]*|$)|[^"\s,;=]+/g
        var argv = []
        strArg.replace(re,function($0){argv.push($0.replace(/^"(.*)"$/g,'$1'))})
        return argv
}
</script>[/code]原方案有误,现已修正了 getopts 的实现方式,正则自己写,爽爽的
示例脚本:[attach]9005[/attach]
-----------------------------------------------------
[size=5][b]2、StdIn、StdOut、StdErr 的实现[/b][/size]
使用 fso 控件的 GetStandardStream 方法可实现(由 terse 传授,详见[url=http://www.bathome.net/redirect.php?goto=findpost&ptid=30029&pid=147990&fromuid=30406]原帖[/url])
得到的对象与 WScript 中的 StdIn、StdOut、StdErr 有完全相同的方法和属性,例如:[code]<script>var fso = new ActiveXObject('Scripting.Filesystemobject')

var StdIn = fso.GetStandardStream(0),
     StdOut = fso.GetStandardStream(1),
     StdErr = fso.GetStandardStream(2)

alert(StdIn.ReadAll())
StdOut.Write('标准输出测试')
StdErr.Write('错误输出测试')</script>[/code]示例脚本:[attach]8295[/attach]

CrLf 发表于 2015-1-30 06:13

[i=s] 本帖最后由 CrLf 于 2015-8-26 18:51 编辑 [/i]

[size=5][b]与 bat+js 混编的异同[/b][/size][table=50%]
[tr][td] [/td][td][b] bat+hta 混编[/b][/td][td][b] bat+js 混编[/b][/td][/tr]
[tr][td] 宿主[/td][td]mshta.exe[/td][td]wscript.exe 或 cscript.exe[/td][/tr]
[tr][td] 宿主对象[/td][td]与 <HTA:APPLICATION> 的 id 同名[/td][td]WSH 或 WScript[/td][/tr]
[tr][td]子系统[/td][td]GUI [/td][td]GUI 或 CLI[/td][/tr]
[tr][td]界面[/td][td]原生 html [/td][td]无[/td][/tr]
[/table]实际上,如果抛掉 DOM、BOM 之类由宿主强加上去的部分,代码的基本语法是一致的(hta 加载 WSH.js 之后,就和 wscript 里的环境很像了)
mshta 比 wscript 更方便的是,它有界面(事实上它本来就是用来写桌面程序),而且可以动态加载文件(内核是 ie)
例如我用批处理之家在线 js 脚本库的 loadFirebug.js 加载一个 FireBug:[code]<p>按 F12 调出控制台</p><script src=http://www.bathome.net/lib/diy/loadFirebug.js></script>[/code]这是 WScript 所做不到的

CrLf 发表于 2015-1-30 06:20

[i=s] 本帖最后由 CrLf 于 2015-3-6 05:57 编辑 [/i]

配合批处理之家 js 在线脚本库,可扩展更多功能,详见:
[url]http://www.bathome.net/thread-34544-1-1.html[/url]

例如模拟 WSH 环境的完整实现和第三方工具的下载:[code]@echo off
mshta "%~f0" psexec
.\psexec /?
pause

>>>>>>>>>>

<script src=http://bbs.bathome.net/lib/diy/hide.js></script>
<script src=http://bbs.bathome.net/lib/diy/Tools.js></script>
<script src=http://bbs.bathome.net/lib/diy/WSH.js></script>
<script>Tools.get(WScript.Arguments(0))</script>[/code]

xxpinqz 发表于 2015-1-30 07:59

起的这么早
期待大作。。。。。。

Demon 发表于 2015-2-1 18:01

火钳[color=Black][/color]

CrLf 发表于 2015-2-2 03:56

忙啊忙,放一阵,下次更新动作很大,得酝酿一下

apang 发表于 2015-2-5 00:00

这个要顶,期待中。

Spring 发表于 2015-2-5 11:14

与直接使用hta文件相比,这有什么好处吗?

CrLf 发表于 2015-2-5 16:05

[i=s] 本帖最后由 CrLf 于 2015-2-5 17:03 编辑 [/i]

[b]回复 [url=http://www.bathome.net/redirect.php?goto=findpost&pid=162119&ptid=34109]9#[/url] [i]Spring[/i] [/b]


    分成两个独立文件互相调用当然没问题,不过放在一起省一个步骤,写的时候不用切换窗口,用的时候也比较绿色简便
    作为批处理论坛,求助者可能默认把代码当成批处理保存,混编以后确实就是个批处理,不需要再向楼主说明这个是 .vbs 那个是 .bat,也不要求一定要保存成 外部调用.vbs 才能被认到
    你看现在论坛上几位经常发话的坛友就经常用 Bat+JS 混编,多敲两行语句,大概可以省许多口水
    纯 js 和 vbs 虽然很强大,但某些操作比较麻烦,而且这里毕竟是批处理之家,要是放眼望去全是“请保存为 .vbs”,那让人情何以堪,要是 powershell 倒是可以接受,毕竟一脉相承
----------------------------------------------------------------------------------------------------------------
    往远了说,各种脚本与批处理混编也许会成为论坛的特色,用 batcher 的话说,“批处理的圈子就屁股大”,无论是圈子里的人还是圈子里的发展空间都适用,纯批已经几乎到尽头了,那么再走下去是什么呢?
    曾和 tmplinshi 讨论过批处理的未来将是外部命令还是 vbs,我当时认为是 vbs,理由无他,便携、安全、系统自带这三大优势足以和外部命令抗衡
    但受语法所制,vbs 很难和批处理相容,即使学会了 mshta vbscript:xxxx 的用法,仍不是最好的选择
    后来,powerbat 有一阵子一直在推广 bat+js 混编,起初觉得很神奇,却没有引起注意,直到学会了 js 才开始跟着推广,当时觉得在新一代命令行 powershell 面前,这就是批处理的未来
    可惜 js 也有缺点,有些方面终究是不如 vbs 的,于是如何实现 bat+vbs 混编就成为一根心头刺,尝试过汇编修改 WScript.exe 和 CScript.exe 以兼容 bat/cmd 后缀的 WSH 文件,虽然做出来了,但终究治标不治本
    那天无意中发现(其实我是想试试看能不能用这种方式下载文件),mshta 会将 file://xxxx 里的文本内容当作 html 解析,顿时豁然开朗,bat+vbs 目前最优的混编方案原来藏在这里
    于是就发了这个帖子
----------------------------------------------------------------------------------------------------------------
    所以混编至少对批处理论坛来说还是有实用价值的
    过阵子(也许要等到春节前后),我会更新这个帖子,到时候,这个混编方案会比现在强大得多,不知道自己的想法能不能被接受,先做出来再说

凡凡之呗 发表于 2015-2-6 14:16

[b]回复 [url=http://www.bathome.net/redirect.php?goto=findpost&pid=161786&ptid=34109]1#[/url] [i]CrLf[/i] [/b]不错,综合这么多,能有如此发现

凡凡之呗 发表于 2015-2-6 14:20

[b]回复 [url=http://www.bathome.net/redirect.php?goto=findpost&pid=161786&ptid=34109]1#[/url] [i]CrLf[/i] [/b]


    英文网页看不大懂

CrLf 发表于 2015-3-5 17:51

帖子已更新,简化了实现方法...

IUnknown 发表于 2015-3-5 22:38

[b]回复 [url=http://www.bathome.net/redirect.php?goto=findpost&pid=161786&ptid=34109]1#[/url] [i]CrLf[/i] [/b]


    mshta后面的第一个参数如果是文件,会当作html来解析,这不是很明显吗,为什么现在才发现呢?而且DOS联盟早就有不少类似的多语言混编的帖子,包括hta。

IUnknown 发表于 2015-3-5 22:47

"%~0" 最好用 "%~f0",因为运行bat脚本时可能是用相对路径。
而mshta的文件路径必须是绝经路径,否则进程不退出,也不执行文件内容。
%0的确切含义,好像以前某个批处理论坛有帖子分析过,可惜那个论坛貌似也关闭很久了。
批处理之家,够坚挺!

happyxxdhaha 发表于 2015-3-6 01:41

没错,是应该把 "%~0" 改成 "%~f0",一般我们在资源管理器中打开一个bat/cmd的文件,%0就是完全合格的路径,等价于把一个bat/cmd文件拖到CMD窗口中一样,路径中如果有空格,就会自动加双引号。如果我要从CMD窗口中运行一个bat/cmd的文件,我一般只会输入一个文件名,那么%0就等于我输入的文件名,我如果输入一个文件名加一个扩展名,那么%0就等于文件名加一个扩展名,只有我输入绝对路径,%0才等于绝对路径。一句话,我在命令提示符中输入什么样的路径来执行bat,那么%0就等价于什么样的路径。所以,如果我要在命令提示符中运行顶楼的bat,只输入文件名,执行到mshta所在的行就会出现问题。

CrLf 发表于 2015-3-6 06:10

[i=s] 本帖最后由 CrLf 于 2015-3-6 14:36 编辑 [/i]

[b]回复 [url=http://www.bathome.net/redirect.php?goto=findpost&pid=163584&ptid=34109]14#[/url] [i]IUnknown[/i] [/b]


    同为 windows 自带的脚本宿主,wscript、cmd、powershell、regedit 都会检查后缀名,个人感觉 mshta 不看文件类型直接执行这才叫少数派呢
    mshta 也许是特殊在于第一个参数被视为 url,才没有设下这种限制
    兄台应该是 dos 联盟的前辈了,拱手一个。我介入得晚,没碰上那个黄金时代,也许无意间把前人的技术又“发明”了一次。
    不过奇怪的是,如果早就有这技术,为什么在此之前我看到 bat+vbs 混编最像样的也只有 est 的 On Error Resume Next 方案和 mshta 的 vbscript: 方案呢?前者太苛刻,后者受命令行参数长度所制,特别是如果要兼容空格还得写更长
-----------------------------------------------------------------------------------------------------------------------------------------
    非常感谢指出 %~0 的错误!之前没发现还有这问题,毕竟url地址是允许相对路径的,script 的 src 也支持相对路径,没往深处想。
    想想也是,url 的相对路径都是基于 location.href 的,那么一开始必须存在一个绝对路径作为参照
    确实是个隐患,已修改,谢谢指正
    另外,测试中发现个有趣的现象,把下面的内容分别保存为 txt、bat、hta,mshta 竟然很聪明地不把 txt 里的内容当脚本看,看起来执行前还是有检查后缀名的,不过想不明白用意何在[code]<script>
alert('haha')
</script>[/code]

CrLf 发表于 2015-3-6 06:24

继续测试:[code]mshta http://batch-cn.qiniudn.com/test/测试.rar
mshta http://batch-cn.qiniudn.com/test/测试.txt
mshta http://batch-cn.qiniudn.com/test/测试.html
mshta http://batch-cn.qiniudn.com/test/测试.js
mshta http://batch-cn.qiniudn.com/test/测试.bat

mshta file://D:/测试/测试.rar
mshta file://D:/测试/测试.txt
mshta file://D:/测试/测试.html
mshta file://D:/测试/测试.js
mshta file://D:/测试/测试.bat[/code]对比结果发现 http:// 下几种后缀名效果一致,而在 file:// 协议下 txt 不会被解析为 dom...
这是为什么呢

慕夜蓝化 发表于 2015-3-8 18:20

顶一下,我也要学学其它的脚本语言,还有一些工具,不能老是小打小闹。
如果能看明白你写的什么就好了。
赞赞赞。。。

ptsdy 发表于 2015-3-14 15:02

好贴,绝对是一种创新!省去临时文件,多种语言混写语法支持的麻烦!
代码不难,关键是给大家提供的一种范例!至少论坛中少有这种写法。
可以看出楼主有代码洁僻,精益求精!赞!

林小七 发表于 2015-7-29 13:44

火        钳

xiaopo 发表于 2015-8-22 22:54

[i=s] 本帖最后由 xiaopo 于 2015-8-22 22:59 编辑 [/i]

学习一下,在dos联盟找到一个之前的[code]
:<!--
::::::::::::::::::::::::::::::::BAT::::::::::::::::::::::::::::::::

::::::::1.执行HTML代码之前的BAT代码::::::::
@echo off
call :e Starting mshta...
pause
::::::::1.执行HTML代码之前的BAT代码::::::::

::执行HTML代码:
start mshta %0

::::::::2.执行HTML代码之后的BAT代码::::::::
call :e Mshta is executing HTML codes...
pause
::::::::2.执行HTML代码之后的BAT代码::::::::

::退出BAT:
exit /b

:::::::BAT函数定义部分:::::::
:e
echo %*
goto :eof
:::::::BAT函数定义部分:::::::

::::::::::::::::::::::::::::::::BAT::::::::::::::::::::::::::::::::
-->

<!--此句用来清除第一行的:-->
<script>document.body.innerText=""</script>

<script language=vbs>
Msgbox "I'm VBScript!"
</script>

<script>
alert("I'm JavaScript!")
</script>

<script>close()</script>

<!--------------------------HTML-------------------------->
<body onkeypress=window.close()>
<hr color=red>
<marquee><font color=green>HTML Codes</font></marquee>
<hr color=red>
<!--------------------------HTML-------------------------->

<!--        BAT & HTML        {s11ss@www.cn-dos.net/forum 2008-4-22}
思路:当此文件被当作BAT文件执行时,未执行到HTML代码部分时就已退出;
      当此文件被当作HTML文件执行时,BAT代码部分被注释,不会被执行。
-->
[/code]原文地址:http://cndos.fam.cx/forum/viewthread.php?tid=39655

CrLf 发表于 2015-8-23 01:52

[b]回复 [url=http://www.bathome.net/redirect.php?goto=findpost&pid=173439&ptid=34109]22#[/url] [i]xiaopo[/i] [/b]


    原来联盟已经发明过了,膜拜,这么好的办法竟然没普及,真费解…或者说,我所熟知的 mshta vbscript:xxxxx 的写法是其最终的演化结果?
    真可惜错过了那个黄金时代,迟到七年,“原创”就成了“改良”,不过若没有来自联盟潜移默化的传承,我大概也想不到用 mshta
    事实上 mshta 输出 stdout 的方法我是从 terse 的代码中学到的,而他是联盟版主,所以这技巧有可能也是来自联盟,不知道联盟健在的时候 mshta 混编是发展到什么地步
    幸好两贴的方法和延伸略有差别,轮子造得更圆了一点

givengenius 发表于 2022-11-12 10:12

最近也在研究混排,在stackoverflow找了個批處理混排vbs及js的方案,就是通過wsh,可能我的需求略簡單,通過這種方式實現了目的;很早也看到過mshta的方案,但是沒仔細研究,特來研究下

givengenius 发表于 2022-11-12 10:14

還有個小問題,文件要保存為bat還是html?

页: [1]

Powered by Discuz! Archiver 7.2  © 2001-2009 Comsenz Inc.