src/GUI/Compile.ps1
|
# 后台 runspace 编译:执行 ps12exe 并把各输出流回写到日志框。 # 编译不在 UI 线程运行,避免界面卡死。 # 建立 MTA runspace 并导入模块;模块只导入一次,后续复用同一 runspace。 function Initialize-GUICompiler { if ($Script:CompileRunspace -and $Script:CompileRunspace.RunspaceStateInfo.State -eq 'Opened') { return } $runspace = [RunspaceFactory]::CreateRunspace() $runspace.ApartmentState = 'MTA' $runspace.ThreadOptions = 'ReuseThread' $runspace.Open() $init = [PowerShell]::Create() $init.RunSpace = $runspace [void]$init.AddScript('param($ModulePath) Import-Module $ModulePath -Force -ErrorAction Stop').AddArgument("$PSScriptRoot/../../ps12exe.psm1") $null = $init.Invoke() if ($init.HadErrors) { foreach ($err in $init.Streams.Error) { Write-GUILog ("Failed to import ps12exe: " + $err.ToString()) } } $Script:CompileRunspace = $runspace $Script:CompilePowerShell = $init } # 本轮编译使用的 Locale 即当前加载语言的 LangID。 function Get-GUICompileLocale { return $Script:LocalizeData.LangID } # 把自上次轮询以来新产生的输出写入日志框。 function Write-GUICompileStreams { $ps = $Script:CompilePowerShell if (-not $ps) { return } $counts = $Script:CompileStreamCounts if (-not $counts) { return } foreach ($streamName in @('Output', 'Information', 'Warning', 'Error')) { $collection = $ps.Streams.$streamName for ($i = [int]$counts[$streamName]; $i -lt $collection.Count; $i++) { Write-GUILog ([string]$collection[$i]) } $counts[$streamName] = $collection.Count } } # Timer 轮询:输出流实时回写,结束时收尾并弹结果框。 function Update-GUICompile { $ps = $Script:CompilePowerShell if (-not $ps) { return } Write-GUICompileStreams $state = $ps.InvocationStateInfo.State if ($state -notin @('Completed', 'Failed', 'Stopped')) { return } if ($Script:CompileTimer) { $Script:CompileTimer.Stop() $Script:CompileTimer.Dispose() $Script:CompileTimer = $null } $Script:CompileRunning = $false if ($Script:refs.CompileButton) { $Script:refs.CompileButton.Text = Get-GUIText 'Button.Compile' } $output = '' try { $output = ($ps.Streams.Output | Out-String).Trim() } catch { } $exitCode = $null try { $exitCode = $ps.Runspace.SessionStateProxy.GetVariable('LastExitCode') } catch { } $errorRecord = $null if ($ps.Streams.Error.Count -gt 0) { $errorRecord = $ps.Streams.Error[0] } $title = if ($Script:LocalizeData) { [string]$Script:LocalizeData.CompileResult } else { Get-GUIText 'Window.Title' } # state=Stopped 时用户主动取消,Stop-GUICompile 已写日志,这里不再弹窗。 if ($state -eq 'Stopped') { return } if ($state -eq 'Failed' -or $exitCode) { $message = '' if ($errorRecord) { if ($errorRecord.CategoryInfo.Category -ine 'ParserError') { $head = if ($Script:LocalizeData) { [string]$Script:LocalizeData.ErrorHead } else { '' } $message = "$head $($errorRecord.Exception.Message)" } else { $target = if ($errorRecord.TargetObject) { [string]$errorRecord.TargetObject.Text } else { '' } $message = (@($errorRecord, $target) -join "`n") } } elseif ($ps.InvocationStateInfo.Reason) { $message = $ps.InvocationStateInfo.Reason.Message } $Script:CompileMessage = $message if (-not $Script:GUISuppressDialogs) { [System.Windows.Forms.MessageBox]::Show([string]$message, $title, [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error) } } else { if (-not $output) { $output = if ($Script:LocalizeData) { [string]$Script:LocalizeData.DefaultResult } else { Get-GUIText 'Log.Done' } } $Script:CompileMessage = $output if (-not $Script:GUISuppressDialogs) { [System.Windows.Forms.MessageBox]::Show([string]$output, $title, [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information) } } } function Start-GUICompile { param([hashtable]$Params = $null) if ($Script:CompileRunning) { return } if (-not $Params) { $Params = Get-ps12exeArgs } Initialize-GUICompiler $Script:CompileRunning = $true if ($Script:refs.CompileButton) { $Script:refs.CompileButton.Text = Get-GUIText 'Button.Cancel' } Write-GUILog (Get-GUIText 'Log.Compiling') $locale = Get-GUICompileLocale $ps = [PowerShell]::Create() $ps.RunSpace = $Script:CompileRunspace [void]$ps.AddScript('param($Params, $Locale) ps12exe @Params -Locale $Locale | Out-String').AddArgument($Params).AddArgument($locale) $Script:CompilePowerShell = $ps $Script:CompileStreamCounts = @{ Output = 0; Information = 0; Warning = 0; Error = 0 } [void]$ps.BeginInvoke() if ($Script:CompileTimer) { $Script:CompileTimer.Stop() $Script:CompileTimer.Dispose() } $Script:CompileTimer = New-Object System.Windows.Forms.Timer $Script:CompileTimer.Interval = 100 $Script:CompileTimer.add_Tick({ Update-GUICompile }) $Script:CompileTimer.Start() } function Stop-GUICompile { $ps = $Script:CompilePowerShell if ($ps -and $Script:CompileRunning) { try { $ps.Stop() } catch { } } Write-GUILog (Get-GUIText 'Log.Cancelled') } function Test-GUICompileRunning { return [bool]$Script:CompileRunning } |