aardio + PowerShell 可視化快速開發獨立 EXE 桌面程式
aardio 可以方便地調用 PowerShell ,PowerShell 中也可以自由調用 aardio 對象與函數。不用帶上體積很大的
System.Management.Automation.dll,直接調用系統組件,可以生成體積很小的獨立 EXE。向下兼容到 .NET 2.0、PowerShell 2.0,支援 Win7,Win8,Win10,Win11 ……
▶ dotNet.ps 擴展庫
aardio 調用 PowerShelll 的功能由基於 dotNet 庫 實現的 dotNet.ps 庫提供。請參考:aardio + .NET 快速開發獨立 EXE 程式,可防 ILSpy 反編譯 。
▶ aardio 調用 PowerShell 命令
我們直接上程式碼看示例:
import console; import dotNet.ps; console.showLoading(" 正在執行PowerShell命令"); console.log( dotNet.ps.command("Get-Command",{"ListImported"}) ); console.pause();
dotNet.ps.command 的第一個參數指定要調用的 PowerShell 命令名,第二個參數用一個表對象指定 PowerShell 命令參數 —— 可以包含僅由參數名字組成的數組成員。
參數表也可以包含由名值對指定的命名參數,例如:
dotNet.ps.command("Get-Command"
,{Name="*Process"} );
要注意參數名前面不需要加 $ 或 – 前綴。
等號前面是參數名(必須是字元串),等號後面是參數值(可傳入 .NET 對象、COM 對象、aardio 對象)。
▶ aardio 調用 PowerShell 腳本
使用匿名參數調用 PowerShell 腳本的示例:
var ps1 = /* for ( $i=0; $i -lt $args.count; $i++){ write-host $args[$i] } */ import dotNet.ps; var output = dotNet.ps(ps1,{ "匿名參數1","匿名參數2","匿名參數3","匿名參數4" }); import console; console.log(output); console.pause();
匿名參數也可以這樣寫:
dotNet.ps(ps1,"匿名參數1","匿名參數2","匿名參數3","匿名參數4");
也可以指定命名參數,如下:
var ps1 = /* # 定義命名參數,參數前加$號,aardio 參數表裡去掉$號 param($username,$password) Write-host $username,$password */ import dotNet.ps; var output = dotNet.ps(ps1,{ username = "名字";//參數名前不要加$ password = "密碼";//參數名前不要加$ }); import console; console.log(output); console.pause();
這裡請注意:
1、PowerShell 通常用 param 聲明參數名稱(函數里也可以這樣寫)。
2、PowerShell 要在變數(或參數名)前加上 $ 符號,在 aardio 中指定 PowerShell 參數時要去掉這個 $ 符號。
dotNet.ps() , dotNet.ps.command() 的傳參數規則是完全一樣的。
▶ PowerShell 調用 aardio 對象
下面就要進入最神奇的部分了,在 PowerShell 里還可以方便地調用 aardio 對象。
我們直接看 aardio 程式碼示例:
var ps1 = /* # 定義命名參數 param($win,$external,$username) # 自由調用參數傳進來的 aardio 對象 $win.msgboxTest("這是 PowerShell 調用 aardio 打開的對話框。") #返回值會自動輸出一行 # 自由調用 aardio 函數 $external.func("參數1","參數2") */ import win; import dotNet.ps; var output = dotNet.ps(ps1,{ win = win; external = { func = function(title,text){ win.msgbox(text,title) } }; });
Win10 / Win11 自帶的 PowerShell 5.1 可以支援這種舒服的寫法。如果要兼容 Win7 只要簡單地調用 dotNet.ps.export( aardio對象 ) 導出參數給 PowerShell 就可以了,不過 Win7 的市場份額已經很小,這種事太追求完美也不好。
▶ 用 JSON 解析 PowerShell 輸出
aardio 程式碼示例:
import console; import dotNet.ps; var psVersion = dotNet.ps.json( `ConvertTo-Json $PSVersionTable.PSVersion`) console.dumpJson(psVersion); console.pause(true);
▶ 捕獲 PowerShell 輸出
很簡單,我們直接看 aardio 程式碼示例:
import console; import dotNet.ps; // PowerShell 輸入都會傳給這個 aardio 函數 dotNet.ps.onWrite = function(str){ console.log(str); } dotNet.ps.command("Get-Command",{Name="*Process"}); console.pause(output);
我們也可以指定 dotNet.ps.onWriteProgress 回調以自定義 PowerShell 進度條,一個例子:
這個進度條範例的源碼在這裡:
aardio 自帶範例 / 調用其他語言 / PowerShell / 進度條
上面範例里有一些方便的小工具,例如作業系統默認禁止單獨運行 *.ps1 腳本文件。上面範例里就提供了一個小工具 —— 可以一鍵開啟或關閉這個許可權:
PowerShell 里有很多 Cmdlet 是用 C# 寫的,而 C# 寫的軟體可以用 ILSpy 直接查看源碼。其實看看一些 Cmdlet 的源碼很有意思,但這個操作步驟有些多。
aardio 自帶的 PowerShell 範例里還提供了一個快速查看 Cmdlet 源碼的工具,可以直接列出所有命令,可以搜索查詢,可以一鍵調用 ILSpy 反編譯出源程式碼:
▶ aardio / PowerShell / .NET 共享應用程式域
用大白話講就是這三者可以直接共享對象,相互調用對象非常方便。
當使用 dotNet.ps 運行 PowerShell 程式碼是在當前進程中運行( 沒有創建新進程,但創建了新執行緒),並且 PowerShell 就運行在 aardio 創建的 .NET 應用程式域中 —— 這時候 aardio / PowerShell / .NET 共享一個應用程式域,這讓我們可以做一些有趣的事。
請看 aardio 程式碼示例:
import dotNet.ps; import dotNet.json; var json = dotNet.ps( ` # 哈希表(數組元素要用逗號分開) $tab = @{ Name = "張三"; Age = "20"; Array = 1,2,3 } # PowerShell 類型放在 [] 裡面,並用 :: 訪問類的靜態成員 [Newtonsoft.Json.JsonConvert]::SerializeObject( $tab ) ` ); var tab = web.json.parse(json); import console console.dump(tab) console.pause()
aardio 庫 dotNet.json 記憶體載入了 .NET 程式集 Newtonsoft.Json.dll,然後我們在 .NET 或是 PowerShell 中就可以直接使用這個程式集導入的類。
注意:PowerShell 將類或類型放在 [中括弧] 內,PowerShell 在聲明或強制轉換類型時都使用這個 [中括弧] ,訪問類的靜態成員使用 :: 而不是圓點 。
下面的例子更進一步:在 aardio 中編譯 C# 程式碼,然後在 PowerShell 中調用該 C# 程式碼引入的類,然後在 C# 中回調 PowerShell 函數,然後在該 PowerShell 函數中回調 aardio 函數:
import win; import console; import dotNet.ps; var compiler = dotNet.createCompiler("C#"); compiler.Source = /****** namespace CSharpLibrary { public class Object { public delegate int TestDelegateType(string str,int a); public event TestDelegateType onTestEvent; public int Test() { return onTestEvent("你好",123); } public static Object New(){return new Object(); } } } ******/ //編譯 C# 程式碼並導入名字空間 compiler.import("CSharpLibrary"); var out,err = dotNet.ps( ` param($win) $obj = [CSharpLibrary.Object]::New() #創建對象 # 添加事件 $obj.add_onTestEvent( { param($str,$a) # 聲明參數 # 調用 aardio 函數 $temp = $win.msgbox("事件被回調了",$str) # return 語句只能改最後一個返回值,與其他語言有較大區別 return $a }) $obj.Test() `,{ win = win; }); console.log(out,err); console.pause(true);
這裡就要注意 PowerShell 有一個非常特別的『 特(大)性(坑)』—— PowerShell 的函數里每句程式碼的默認輸入都會增加一個返回值,例如您執行下面的 PowerShell 程式碼:
# 添加事件 $obj.add_onTestEvent( { param($str,$a) $win.msgbox("事件被回調了",$str) return $a })
這裡的返回值實際上有兩個,一個是 $win.msgbox() 返回的 object,另一個是 return 返回的 $a,最終返回值是一個數組。然後就會報返回值與 C# 委託回調的返回值類型不匹配。
避免上面這個問題也很簡單,把程式碼放到一個賦值語句里就不會增加返回值了,正確寫法:
$temp = $win.msgbox("事件被回調了",$str)
▶ 創建管道調用 PowerShell.exe
我們還可以用 aardio 中的 procee.popen 創建進程管道,這樣就可以讀寫 PowerShell.exe 的輸出輸入,並且隱藏黑窗口。
下面是一個例子:
import console; import process.popen; console.showLoading(" 請稍候,正在調用 PowerShell"); var prcs = process.popen.ps(`-Command`,`&{ function Get-Version { ConvertTo-Json( $PSVersionTable.PSVersion ) } Get-Version }`); //讀取進程輸出 var json = prcs.readAll(); //解析返回的 JSON import web.json; var psVersion = web.json.parse(json); console.dump(psVersion); console.pause();
這裡要注意,PowerShell 會將僅用大括弧包含的 PowerShell 作為字元串輸出,在前面加上一個 & 字元才會執行該語句塊。
▶ 調用更多程式語言
aardio 中還可以非常方便地調用 C語言、C++、C#、Java、Python、R、Javascript、Node.Js、Fortran、VB、Flash ActionScript、PHP、VBScript、PowerShell、NewLISP、AutoLISP、Delphi、FreeBASIC、Ruby、Rust、Julia、Nim、Go 語言、批處理 …… 甚至可以直接嵌入彙編機器碼並且轉換為普通的 aardio 函數。


