这是AARDIO微信公众号文章。因为该作者经常发了文章又删掉,这里记录一下。
在C#中可以调用PowerShell,其他语言就很麻烦了,好在 aardio 可以方便的调用C#,实际上我们要调用的是 System.Management.Automation.dll, 包括微软的 PowerShell.exe 实际上也是调用这个DLL。C#这类开源的代码有很多,在开源项目UnmanagedPowerShell中我提取了PowerShellRunner.cs – 需要用到的只有这一个文件。
但是这个C#调用PowerShell 的代码有个问题,需要带上 2MB的 System.Management.Automation.dll,并且也不能内存加载,只能在指定的PowerShell 3以及 .Net 4.0 上运行。这个就不太好了,我们用 aardio 写程序,不但要足够的小,还有有最好的兼容性。所以我决定直接在 aardio 中编译这个C#代码,aardio 有一个好处就是可以在运行时动态的引用DLL,下一步我们就需要找到系统自带的 System.Management.Automation.dll,但是这个DLL的位置比较奇葩,每个版本位置都不一样,网上的讨论都是到PS里敲一下命令行拿到DLL路径再调用,这个就更不方便了。还好我们用 aardio 解决这个问题比较方便,在 aardio 里添加一句 compile.Reference("System.Management.Automation"); 这个问题搞定了。不用再带几MB的DLL,几句代码就可以调用PowerShell 了,而且自适应系统安装的PowerShell和.Net版本。
这中间还遇到另外一个坑,PowerShellRunner.cs在.Net 4.0上可以跑,.Net2.0下一大堆的报错,然后再把C#代码进行修改,华而不实的新版语法糖干掉,好看没有用,好用才是最重要的对吧。
dotNet.ps 的代码我建议大家看看,里面有几个地方我写了注释,可能是平时比较容易踩到的坑。例如我们调用C#函数的代码:
powerShellRunner.InvokeScript(command,!!useLocalScope);//useLocalScope参数必须是布尔类型,以匹配C#函数签名
powerShellRunner.InvokeScript是一个C#函数,第2个参数useLocalScope是bool类型,但是我们在 aardio 里很多非 bool 类型可以自动转换,例如我们传一个0,null都是在aardio中合法的,但是C#是静态语言,你传个0,他就因为找不到第二个参数是数值类型的对应函数而报错,所以我们要使用 !!useLocalScope 转换为真正的 bool 类型值。同样的还有数组类型,例如C#的函数参数是string[]数组类型,如果我们在aardio里用{}传一个空数组进去,C#无法判断这是什么数组,然后又会找不到对应签名的函数而报错。这一点在aardio与C#交互时要特别注意。
v29.1 还对控制台进行了改进,现在多数控制台相关的应用都用到了ANSI转义序列,而Windows只有Win10才能支持这个功能。这个就不太好了,aardio 需要尽可能的提供最大兼容性,为了解决这个问题,我找了一个开源的组件 ansion.dll,很小的dll只有47kb,体积相当于一个极小的图标文件了。这东西用起来其实非常简单,我们一句 raw.loadDll("ansion.dll") 就可以让控制台支持ANSI转义码了。
当然我们为了尽可能的完美一些,还需要判断系统是否已经支持ANSI转义码,只有在不支持时才调用ansion组件。于是我们仔细改进了 console 库,写几句代码测试一下效果很好:
import console;
console.log('
\e[30m 字体黑色
\e[37m 字体白色
\e[40m 黑色背景
\e[41m 红色背景
光标上移2行:\e[2A
光标下移2行:\e[2B
光标右移2字符:\e[2C
光标左移2字符:\e[2D
');
console.pause(true);
意外的是,在个别系统上 ansion 组件会导致程序崩溃,崩溃多不好呀,于是仔细地找原因 – 其实是一个低级错误。raw.loadDll("ansion.dll") 加载了这个 dll,但是 aardio 的内存回收看到这个 dll没有代码继续使用,所以就不客气的回收了,然后 dll 走的时候没有做清理还原的工作就出错了。解决的方法也很简单,使用代码 console.consion = raw.loadDll("ansion.dll") 保持一个引用就可以了,或者我们可以换一个低调的名字,例如 console["$(ANSION32.DLL)"] ,最后我们还需要小改一下,把这个 dll 直接放到内存里加载,最终代码:
console["$(ANSION32.DLL)"] = ..raw.loadDll($"~\lib\console\.res\ANSI32.dll","ANSION32");
这样我们又可以愉快的生成独立exe文件,不用再带一个dll了。
多年以来,aardio 始终是这样把小、轻、快放到第一位,今天看了一下 aardio,发行包的体积又减小了一些,现在是 6.3MB了,有趣的是,aardio 的功能越做越多,体积却越来越小,不仅是 aardio 小,aardio 做的软件都很小,在 aardio 开始页每一条就是开源项目链接,大家可以点进去看看,对了,如果大家觉得这些开源软件好用,或者开源的代码对你有所帮助,请随手点个赞,我看到有些 aardio 开源项目一直在卖力地更新,但点赞的不多,这个就不好了,执心分享的我们要多鼓励,多点赞,谢谢大家。