批处理与其他语言混合编程

来源:百度文库 编辑:神马文学网 时间:2024/04/28 06:59:09
Wikipedia,自由的百科全书
(重定向自Hybird)
目录 [显示隐藏]
1 综述
2 与汇编集成
2.1 早期方法
2.2 传统的echo大法
2.3 方便的prompt大法
2.4 经典的more大法
2.5 强悍的ASCode
2.6 巧妙的.com文件头
3 与VBS集成
3.1 传统的echo大法
3.2 国外的find大法
3.3 经典的more大法
3.3.1 Vacum 的方法
3.4 方便的mshta大法
3.5 让WSH直接解析bat
4 与.NET语言集成
5 与其他语言集成
6 附加信息
综述
脚本类语言作为21世纪的一种先进的高级语言,其特征是整合(glue),批处理有极强的其他语言整合能力,目前比较成熟的方案有下面所述几种,通过和其他计算机语言的整合,极大的扩展批处理的功能,使得原本用批处理不可能实现的工作,通过整合汇编/VBS/.NET可以轻松达到惊人的效果。
与汇编集成
传统的DOS和经典的CMD都支持一个外部命令debug所以使得批处理有了汇编方面的扩展能力,debug命令支持重定向输入代码,所以给了代码极大的灵活性
早期方法
早期的批处理功能十分弱,甚至嵌用汇编也不是那么直接,比如自嵌后直接重定向的例子
@echo offgoto starte 100 B0 13 CD 10 C4 2F AA 13 C7 64 13 06 6C 04 50 B4 01 CD 16 58 74 F0 B8 03 00 CD 10 C3r cx1cn mini_ani.comwq:startdebug < %0 >nulmini_ani.comdel mini_ani.compause
find反过滤的例子
它的优势在于可以通过find过滤嵌入多个脚本
@echo offe 100 B0 13 CD 10 C4 2F AA 13 C7 64 13 06 6C 04 50 B4 01 CD 16 58 74 F0 B8 03 00 CD 10 C3r cx1cn mini_ani.comwq@find "@" /v < %0 | debug >nul@mini_ani.com@del mini_ani.com@pause传统的echo大法
通过echo命令重定向标准输出到临时文件,然后用debug执行这个临时文件里的命令,这个方法比较通用,批处理输出文件都是用的这个方法,不足是需要产生临时文件论坛讨论 (http://www.cn-dos.net/forum/viewthread.php?tid=23573)
echo D C000:000> v.datecho D>>v.datecho D>>v.datecho Q>>v.datDebug.exe < v.dat >info.txt@echo offecho o 70 17 >tmp.txtecho o 71 ff >>tmp.txtecho Q >>tmp.txtdebug prompt命令支持一个特殊的参数 $_ ,改参数表示换行,所以在批处理中灵活应用可以写出紧凑的汇编代码论坛讨论 (http://www.cn-dos.net/forum/viewthread.php?tid=26591)
echo exit|%ComSpec% /k prompt e 100 B4 00 B0 12 CD 10 B0 03 CD 10 CD 20 $_g$_q$_|debug>nul经典的more大法
more支持一个 +n 参数,表示从文件的指定行开始输出,我们利用这个参数把批处理本身尾部的一些汇编代码直接通过 | 管道直接输出到debug命令,该方法最早可能是论坛网友上[doscc (http://www.cn-dos.net/forum/viewpro.php?uid=52853)]提出的论坛讨论 (http://www.cn-dos.net/forum/viewthread.php?tid=21950)
<"%~f0" more +2 |debug & 0.comgoto:eofe100 B0 13 CD 10 C4 2F AA 11 F8 64 13 06 6C 04 EB F6rbx0rcx10n 0.comwq强悍的ASCode
ASCode论坛讨论 (http://www.cn-dos.net/forum/viewthread.php?tid=26795)
@echo offchcp 437>nul&graftabl 936>nulecho hP1X500P[PZBBBfh#b##fXf-V@`$fPf]f3/f1/5++u5x>in.comset /p password=请输入密码:这类汇编程序的特殊性在于,所有的代码全部分布于ASCII码表的可显示字符范围中,当然这样的程序不是碰巧得到的,而是人为的构造出来的,其中需要用到许多技巧。比如最常见的中断调用代码int 21(CD 21),因为不在ASCII可显示字符范围内,所以用到许多压栈、出栈、增减代码来构造,所以它的代码段是动态变化的。这样的代码被叫做 ASCODE,这样的技术被称作 ASCII Assemble,一门即将消失的技术,可想而知,这样的代码构造起来是困难的,在网上流传的ASCODE只有很少量的是人为构造的,因为已经有成熟的技术可以将任何二进制文件转变为ASCODE,这样的过程叫encode。而ASCODE执行的过程需要decode,合称codec,codec 的算法已知的超过4种,比较有名的应该是Herbert Kleebauer的算法,不过它要求原程序必须有org 170H的类似标记,因为前面的文件头被用来存放decode代码。
巧妙的.com文件头
据说这个是袁哥写的病毒天极网的分析资料 (http://www.yesky.com/20000519/63089.shtml)
:0jeX4e-005POP]hWeX5ddP^1,FFFFF1,FFF1,4rP^P_jeX4aPY-x-AAR`0`*=00uPBOIAAAAFKAOBPIDMCBALEAJMNCBJALIAAEMMNCBFEGIGFCAENGBGDHCGPHGGJHCHFHDCAGJHDCAGDGPGNGJGOGHCACOCOCOCOCOCOANAKCEAAqqqq@ECHO OFFCOPY %0 /B C:\BATVIR.COM /B /YC:\BATVIR.COMDEL C:\BATVIR.COM
这段代码有什么巧妙指出呢?第一句的开头, : 冒号告诉 cmd.exe ,这句是个GOTO语句的标识符,cmd.exe会直接跳过这一句,也就是当作注释了,但是,后面的批处理把自身copy为batvir.com,这就很讲究了, .com文件是以 : 开头的一段ASCode代码!所以这种ASCode比上一种更加高级,因为必须以 : 作为ASCode的开头。
与VBS集成
在命令行下调用VBS/JS用cscript命令,由于cscript只能读取文件,不接受重定向和管道的输入,所以只能用echo或者more来生成一个临时脚本文件
传统的echo大法
与批处理不同的是,VBS有很多特殊字符,例如>在批处理中代表重定向输出,在VBS语法里代表 大于,所以使用 echo需要用 ^ 来转义特殊符号
echo msgbox 3^>2 >v.vbscscript v.vbs国外的find大法
利用find命令过滤出VBS代码的一个特定 'VBS,这样可以嵌入多段VBS代码到bat里,例如:
@echo off & setlocal enableextensions:: Make a temporary folderif not exist c:\mytemp mkdir c:\mytemp:: Build a Visual Basic Scriptfindstr "'%skip%VBS" "%~f0" > c:\mytemp\tmp$$$.vbs:: Run it with Microsoft Windows Script Host Version 5.6cscript //nologo c:\mytemp\tmp$$$.vbs:: Call the command line script the script host builtcall c:\mytemp\tmp$$$.cmd:: Clean upfor %%f in (c:\mytemp\tmp$$$.vbs c:\mytemp\tmp$$$.cmd) do if exist %%f del %%frmdir c:\mytemp:: Show the resultecho Day Number dn_=%dn_%endlocal & goto :EOF''The Visual Basic ScriptConst ForReading = 1, ForWriting = 2, ForAppending = 8 'VBSDim DateNow, fso, f 'VBSDateNow = Date 'VBSSet fso = CreateObject("Scripting.FileSystemObject") 'VBSSet f = fso.OpenTextFile("c:\mytemp\tmp$$$.cmd", ForWriting, True) 'VBSf.Write "@set dn_=" & DatePart("y", DateNow) 'VBSf.Close 'VBS经典的more大法
同上面的more大法,优点是不需要考虑特殊字符的问题,缺点是代码灵活性不高,添加了代码就需要修改 +n 的值
< "%~f0" more +3 >v.vbscscript //nologo v.vbsgoto:eofmsgbox nowwscript.echo ">>>CN-DOS<<<"wscript.stdin.readline
Vacum 的方法
最近在写几个Bat,在Google 上找到这里,顺便把我的方法也贴到这里来,和上面的Find 、more 方法原理差不多。但感觉灵活方便许多。代码如下,不是很复杂,就不多说明了。
:: Make all the code into one bat file@echo OFFIF "%1"==":_GET_LINES_" GOTO :_GET_LINES_REM Your code hereREM Example( CALL %0 :_GET_LINES_ ############ ) | MORE( CALL %0 :_GET_LINES_ __SQLPLUS__ ) | MOREREM 这一部分用来取数据。goto :EOF:_GET_LINES_SETLOCAL ENABLEDELAYEDEXPANSIONSET LINE_TAG=%2SET BEGIN_LINE=0SET TOTAL_LINE=0SET CURLINE=0for /f "usebackq delims=: tokens=1 " %%i in ( ` findstr /N /R /C:^^^^%LINE_TAG% %0 `) DO set BEGIN_LINE=%%i & goto __GET_BEGIN_LINE_OK:__GET_BEGIN_LINE_OKfor /f "usebackq delims=: tokens=1 " %%i in ( ` (for /f "skip=!BEGIN_LINE! tokens=*" %%j in (%0^) do @echo %%j ^) ^| findstr /N /R /C:^^^^%LINE_TAG% `) DO set TOTAL_LINE=%%i& goto __GET_END_LINE_OK:__GET_END_LINE_OKfor /f "skip=%BEGIN_LINE% tokens=*" %%i IN (%0) DO ( ( SET /A CURLINE+=1 ) & ( if !CURLINE! LSS %TOTAL_LINE% (if not "A%%i"=="A" @echo %%i ) ) )ENDLOCALGOTO :EOFREM 下面是数据部分的内容############Hello This Just a Test限制,前导空格、空行会被过滤掉,可以在上面的for 语句中增加 delims= 选项来解决,但同时会带来新的问题############__SQLPLUS__SELECT * FROM DUAL;select * from dual;__SQLPLUS__方便的mshta大法
该方法由est首创,巧妙利用了Windows系统里自带的javascript:和vbscript:协议使得在批处理中能够在一行的狭小空间里插入简短的VBS/JS代码论坛讨论 (http://www.cn-dos.net/forum/viewthread.php?tid=21017)
mshta "javascript:new ActiveXObject('SAPI.SpVoice').Speak('Hi, CN-DOS guys!');window.close();"
事实上使用 iexplore.exe 和 Helpctr.exe 也可以,不过mshta.exe的权限相对要高一点
让WSH直接解析bat
这个方法也是est首创论坛讨论 (http://www.cn-dos.net/forum/viewthread.php?tid=25333)
:On Error Resume NextSub batecho off & clsecho Batching_codez_here_following_vbs_rules & pausestart wscript -e:vbs "%~f0"Exit SubEnd SubMsgBox "This is vbs"
代码解释
:On Error Resume Nextcmd.exe 识别成一段注释
wscript.exe 这样识别, : 在vbs语法里代表分行,然后 On Error Resume Next,也就是让WSH忽略一些错误
start wscript -e:vbs "%~f0"
cmd.exe 识别成:启动 wscript.exe ,其参数是: ① -e:vbs 设定以vbs解析文件自身 ② "%~f0" 指这个批处理本身。
wscript.exe 把这句识别成:调用一个叫 start 的函数,函数参数是 wscript 这个变量,然后用这个函数的结果来 减去 e。接下来是又是一个 : ,分行,然后又是调用一个名叫 vbs 的函数,参数是字符: "%~f0"
这句是最为精巧的,因为它成功的让 vbs 引擎解释了一段批处理,而且没有错误!当然这些 start()、vbs()函数是不存在的,但是会被 cmd.exe 当成命令执行。为什么不用 wscript //e:vbs "%~f0" 来执行呢?vbs解析会出错的
这段代码的核心思想已经介绍完毕了。下面,为了让 批处理 以vbs调用其自身后,马上退出,我们需要 exit 或者 goto :eof,但是 goto call exit 在vbs又是一个关键词,所以我们只能用符合 vbs 语法的 exit sub,所以我们在第二句加一个 sub bat,其实 cmd.exe 寻找了一个叫 sub.exe 的命令,但是这个命令是不存在的,cmd.exe 跳过。然后在 6、7 句加一个 exit sub 以及 end sub,让 批处理结束,同时又符合 vbs 的语法
那个 echo off & cls ,批处理的意思就是相当于 @echo off ,但是 vbs 不认 @ 符号,所以改成 echo off & cls , vbs 可以解析为,调用一个叫 echo() 的函数,参数为 off & cls ,也就是两个字符串 off 和 cls 相加
这段代码的好处是:不用生成临时文件。其实用 echo 或者 more 或者 find 来生成临时vbs很浪费系统资源的,用我写的这段代码,就完全免去了这些麻烦。直接混合编程,以 start wscript -e:vbs "%~f0" 为界限,上面写 批处理,下面写 vbs,并行不悖!
与.NET语言集成
安装了 .NET Framework 之后,系统就多了一个强势语言的编译工具,在 C:\Windows\Microsoft.NET\Framework\v*\下,我们可以在批处理中输出代码然后调用这些编译器来现场生成exe让批处理调用。这些编译器有,C# 的 csc.exe,VB.NET的vbc.exe,JScript.NET的jsc.exe,VJ#的vjc.exe,这里给出 C# 的例子,由于 C# 是一种语法严格的语言,所以推荐用more直接生成源代码并且编译论坛讨论 (http://www.cn-dos.net/forum/viewthread.php?tid=26751)
@echo offset "dnfpath=C:\Windows\Microsoft.NET\Framework"set "est=DO_NOT_ZT_WITHOUT_PERMISSION"for /f "delims=" %%v in ('dir /ad /b %dnfpath%\v?.*') do (if exist "%dnfpath%\%%v\csc.exe" set "cscpath=%dnfpath%\%%v\csc.exe")< "%~f0" more +17 > "%temp%\estTrayTip.cs"%cscpath% "/out:%cd%\estTrayTip.exe" "%temp%\estTrayTip.cs"estTrayTip.exe C:\Windows\System32\acwizard.ico 看什么看 没见过批处理啊?没见过任务栏的汽泡信息啊?见过了吧?见过了顶electronixtar的帖子。 2:exe的参数解释:estTrayTip.exe 图标路径 标题 内容 提示图标类型Error、Info、None、Warning,这里取2=Info。每个参数都必须正确填写>nul ping 127.1 -n 1del estTrayTip.exegoto:eof:estTrayTipusing System;using System.Windows.Forms;using System.Drawing;namespace estTrayTip{class Program{static void Main(string[] args){NotifyIcon estIcon = new NotifyIcon();estIcon.Icon = new Icon(args[0]);estIcon.Visible = true;ToolTipIcon estToolTipIcon = new ToolTipIcon();switch(args[3]){case "1":estToolTipIcon = ToolTipIcon.Error; break;case "2":estToolTipIcon = ToolTipIcon.Info; break;case "3":estToolTipIcon = ToolTipIcon.None; break;case "4":estToolTipIcon = ToolTipIcon.Warning; break;}estIcon.ShowBalloonTip(1,args[1],args[2],estToolTipIcon);}}}与其他语言集成
其他语言,例如Python,Perl等和批处理集成,方法和上面的都大同小异
ruby和CMD脚本的混杂编写示例
#!/usr/bin/ruby@rem = <本wiki持续更新中,转载请注意版本更新,不要误人之弟
作者:est,联系方式:(Email & MSN)electronicstar@126.com
最后更新:2007-1-17 17:22 感谢lxmxn的支持,感谢ccwan帮助测试代码