我一直在使用Powershell一段時間,它不是理想的編程環境,但卻被我的程序困住了。跑馬燈進度條在Powershell中凍結
我的程序是一個帶有選取框進度條和搜索作業的GUI。
我的程序執行的操作:使用Powershell運行腳本後,如果模式爲MTA,它將在STA模式下重新啓動Powershell。之後,它會要求提供一個文件夾位置。輸入文件夾位置後,它將開始搜索作業,並將搜索文件的位置。每個文件都將被存儲到一個數組中。該數組將打印到將保存在桌面上的tempfile.txt中。同時,該作業正在搜索GUI將使用滾動進度條顯示錶單的文件。
我的程序需要做什麼:在作業完成搜索和存儲文件後,它必須關閉表單。
我已經嘗試過使用$ formSearchingFiles.Close()命令,但我注意到喬布斯無法關閉他們的「父」線程,所以這項工作將無法關閉窗體。
我也嘗試使用Wait-Job cmdlet解決問題,但然後「選框進度」欄會凍結,否則表單根本不會顯示。
我已經看過很多互聯網的解決方案,但我找不到適合這個問題的。我正在考慮多處理,但我不知道這是否可能在PowerShell 2.0中(我限制在2.0或更低)。
我也不知道Search-Job是否可以通知主線程完成任務,以便主線程可以繼續執行程序,而不凍結進度條。
我希望我已經解釋了有關程序和我的問題。
# Get the path of the script
$scriptPath = ((Split-Path $script:MyInvocation.MyCommand.Path) + "\")
$scriptName = $MyInvocation.MyCommand.Name
$script = $scriptPath + $scriptName
# Check if powershell is running in STA(Single Threaded Apartment) or MTA(Multi Threaded Apartment) mode.
# If it is running in MTA mode then restart Powershell in STA mode.
if ([threading.thread]::CurrentThread.GetApartmentState() -eq "MTA")
{
Write-Host Restarting Powershell in STA mode
& $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe -sta "& {&'$script'}"
}
else
{
$folderPath = $currentFolderLocation.Text
$tempFile = $currentStagingLocation.Text
$tempFile += "\fileArray.txt"
function OnApplicationLoad {
return $true #return true for success or false for failure
}
function OnApplicationExit {
$script:ExitCode = 0 #Set the exit code for the Packager
}
function Call-Searching_pff {
[void][reflection.assembly]::Load("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][reflection.assembly]::Load("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][reflection.assembly]::Load("System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
[void][reflection.assembly]::Load("System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][reflection.assembly]::Load("System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][reflection.assembly]::Load("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][reflection.assembly]::Load("System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
[void][reflection.assembly]::Load("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][reflection.assembly]::Load("System.ServiceProcess, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
[System.Windows.Forms.Application]::EnableVisualStyles()
$formSearchingFiles = New-Object 'System.Windows.Forms.Form'
$label = New-Object 'System.Windows.Forms.Label'
$progressbar = New-Object 'System.Windows.Forms.ProgressBar'
$InitialFormWindowState = New-Object 'System.Windows.Forms.FormWindowState'
$FormEvent_Load={
$folderPath = &read-host "Enter path"
$tempFile = (([Environment]::GetFolderPath("Desktop")) + "\tempfile.txt")
$SearchJob = Start-Job -scriptblock {
param ($folderPath, $tempFile)
$fileArray = @()
# Get all files and folders under the specified path
$items = Get-ChildItem -Path $folderPath -Recurse
foreach ($item in $items)
{
# Check if the item is a file or a folder
if (!($item.PSIsContainer))
{
# Extract path of file with path of entered folder
$extractedPath = $item.FullName
$extractedPath = $extractedPath.Replace($folderPath, "")
$fileArray += $extractedPath
}
}
# Save array in temporary file
$fileArray | out-file $tempFile
$formSearchingFiles.Close() #Does not work inside job :(
} -ArgumentList @($folderPath, $tempFile)
}
$Form_StateCorrection_Load=
{
#Correct the initial state of the form to prevent the .Net maximized form issue
$formSearchingFiles.WindowState = $InitialFormWindowState
}
$Form_Cleanup_FormClosed=
{
#Remove all event handlers from the controls
try
{
$formSearchingFiles.remove_Load($FormEvent_Load)
$formSearchingFiles.remove_Load($Form_StateCorrection_Load)
$formSearchingFiles.remove_FormClosed($Form_Cleanup_FormClosed)
}
catch [Exception]{ }
}
# formSearchingFiles
$formSearchingFiles.Controls.Add($label)
$formSearchingFiles.Controls.Add($progressbar)
$formSearchingFiles.ClientSize = '394, 122'
$formSearchingFiles.FormBorderStyle = 'FixedDialog'
$formSearchingFiles.MaximizeBox = $False
$formSearchingFiles.Name = "formSearchingFiles"
$formSearchingFiles.StartPosition = 'CenterScreen'
$formSearchingFiles.Text = "Compatibility Checker"
$formSearchingFiles.add_Load($FormEvent_Load)
# label
$label.Location = '12, 27'
$label.Name = "label"
$label.Size = '368, 26'
$label.TabIndex = 1
$label.Text = "Searching for files, please wait.."
$label.TextAlign = 'MiddleCenter'
# progressbar
$progressbar.Location = '12, 68'
$progressbar.MarqueeAnimationSpeed = 40
$progressbar.Name = "progressbar"
$progressbar.Size = '370, 30'
$progressbar.Style = 'Marquee'
$progressbar.TabIndex = 0
#Save the initial state of the form
$InitialFormWindowState = $formSearchingFiles.WindowState
#Init the OnLoad event to correct the initial state of the form
$formSearchingFiles.add_Load($Form_StateCorrection_Load)
#Clean up the control events
$formSearchingFiles.add_FormClosed($Form_Cleanup_FormClosed)
#Show the Form
return $formSearchingFiles.ShowDialog()
} #End Function
#Call OnApplicationLoad to initialize
if((OnApplicationLoad) -eq $true)
{
#Call the form
Call-Searching_pff | Out-Null
#Perform cleanup
OnApplicationExit
}
}
爲什麼要使用一個WinForms進度條什麼特別的原因?你見過write-progress cmdlet嗎?它可以在控制檯中爲你呈現一個進度條,而不必擔心所有這些STA垃圾。 – x0n
這個程序只是我的完整程序的一部分,我使用Windows窗體來製作一個漂亮的GUI,它比控制檯中的文本更加用戶友好。我剛剛發佈了這篇文章,因爲只有在這篇文章中我遇到了一個問題。 – LittleOne
我可能有解決方案。通過使用同步哈希表作爲2個線程之間的「通信鏈接」。還沒有測試過。 – LittleOne