PowerShell会话挂起:如何正确释放表单、关闭Runspace及会话?
问题解答:PowerShell等待GIF窗口与Runspace资源释放的正确实现
原代码阻塞原因
原代码执行到$Powershell.EndInvoke($Handle)时卡住,核心问题有两个:
- Runspace脚本中调用
ShowDialog()会阻塞Runspace线程,必须等窗口关闭才会继续执行。但主线程先调用$Gif_Form.One.Dispose()强制释放窗口资源,导致Runspace的ShowDialog()处于异常状态,EndInvoke()无法正常完成。 - Runspace脚本内重复创建
$Gif_Form.One对象,覆盖了主线程初始化的实例,同步哈希表的跨线程共享逻辑被破坏。
改写代码的可行性
改写后的代码完全可以采用,它精准解决了原代码的问题,同时优化了逻辑:
- 将表单和PictureBox的创建、GIF加载移到主线程完成,避免跨线程重复创建对象,减少资源冗余和同步问题。
- 主线程完成
Get-ChildItem后,先调用$Gif_Form.One.Close()主动关闭窗口,让Runspace中的ShowDialog()退出阻塞,此时$Powershell.EndInvoke($Handle)能正常执行,不会卡住。 - 把异步加载
LoadAsync()改为同步Load(),因为GIF在主线程提前加载完成,避免Runspace中异步加载可能的资源同步问题。
原代码
Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing Clear-Host $Gif_Form = [hashtable]::Synchronized(@{}) $Gif_Form.One = New-Object system.Windows.Forms.Form $Runspace = [Runspacefactory]::CreateRunspace() $Runspace.Open() $Runspace.SessionStateProxy.SetVariable('Gif_Form',$Gif_Form) $Powershell = [Powershell]::Create() $Powershell.Runspace = $Runspace $Powershell.AddScript( { Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing $Gif_Form.One = New-Object system.Windows.Forms.Form $Gif_Form.One.Text = "PLEASE WAIT..." $Gif_Form.One.Location = New-Object System.Drawing.Size(1200,100) $Gif_Form.One.StartPosition = "Manual" $Gif_Form.One.Size = New-Object System.Drawing.Size(166,160) $Gif_Form.One.AutoSizeMode = "GrowAndShrink" $Gif_Form.One.BackColor = "RED" $Gif_Form.One.ControlBox = $FALSE $Gif_Form.One.Enabled = $TRUE $Gif_Form.One.Add_Shown({$Gif_FORM.Activate()}) $PictureBox = New-Object Windows.Forms.PictureBox $PictureBox.LoadAsync("G:\Dog Chasing Tail.gif") $PictureBox.BackColor = "RED" $PictureBox.SizeMode = "AutoSize" $Picturebox.Visible = $TRUE $X = 25 $Y = 10 $Picturebox.Location = New-Object System.Drawing.Size($X,$Y) $Gif_Form.One.controls.add($PictureBox) $Gif_Form.One.Visible=$FALSE $Gif_Form.One.ShowDialog() }) $Handle = $Powershell.BeginInvoke() Write-Host "Starting GET-ChildItem command..." $Folders = $Null #---------------------------------------------------------# $Folders = Get-Childitem -Path C:\ ` -Directory ` -Recurse ` -ErrorAction SilentlyContinue #---------------------------------------------------------# # Test the automatic variable $? to see if the previous # # Command has completed successfully. If $? is equal to # # $TRUE, then the command completed successfully. # #---------------------------------------------------------# Write-Host "...Get-ChildItem is done." #---------------------------------------------------------# # Get rid of the Powershell session and runspace # # value was computed. # #---------------------------------------------------------# $Gif_Form.One.Dispose() $Powershell.EndInvoke($Handle) Write-Host "Did I get this far?" $RunSpace.Close() $Powershell.Dispose() Foreach ($PSItem in $Folders) { Write-Host $PsItem.Name -BackgroundColor Black ` -ForegroundColor Green }
改写后的代码
Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing Clear-Host $Gif_Form = [hashtable]::Synchronized(@{}) $Gif_Form.One = New-Object system.Windows.Forms.Form $Gif_Form.One.Text = "PLEASE WAIT..." $Gif_Form.One.Location = New-Object System.Drawing.Size(1200,100) $Gif_Form.One.StartPosition = "Manual" $Gif_Form.One.Size = New-Object System.Drawing.Size(166,160) $Gif_Form.One.AutoSizeMode = "GrowAndShrink" $Gif_Form.One.BackColor = "RED" $Gif_Form.One.ControlBox = $FALSE $Gif_Form.One.Enabled = $TRUE $PictureBox = New-Object Windows.Forms.PictureBox $PictureBox.Load("G:\MyFunctions\Dog Chasing Tail.gif") $PictureBox.BackColor = "RED" $PictureBox.SizeMode = "AutoSize" $Picturebox.Visible = $TRUE $Picturebox.Location = New-Object System.Drawing.Size(25,10) $Gif_Form.One.Controls.add($PictureBox) $Runspace = [Runspacefactory]::CreateRunspace() $Runspace.Open() $Runspace.SessionStateProxy.SetVariable('Gif_Form',$Gif_Form) $Powershell = [Powershell]::Create() $Powershell.Runspace = $Runspace $Powershell.AddScript( { $Gif_Form.One.Visible=$FALSE $Gif_Form.One.Showdialog() }) $Handle = $Powershell.BeginInvoke() $Folders = $Null #---------------------------------------------------------# Write-Host "Starting GET-ChildItem command..." $Folders = Get-Childitem -Path C:\ ` -Directory ` -Recurse ` -ErrorAction SilentlyContinue Write-Host "...Get-ChildItem is done." #---------------------------------------------------------# # Get rid of the Powershell session and runspace # # value was computed. # #---------------------------------------------------------# $Gif_Form.One.Close() $Gif_Form.One.Dispose() $Powershell.EndInvoke($Handle) $RunSpace.Close() $Powershell.Dispose() Foreach ($PSItem in $Folders) { Write-Host $PsItem.Name -BackgroundColor Black ` -ForegroundColor Green }
内容的提问来源于stack exchange,提问作者Fr. Eugene
相关产品推荐
相关产品推荐

