mirror of
https://github.com/ChrisTitusTech/winutil.git
synced 2026-08-09 09:31:15 +10:00
Fix Show Installed Apps reliability and selection (#4850)
* Fix Windows PowerShell runspace cleanup callback * Fix installed app package ID matching * Synchronize installed app selection UI * Streamline installed app detection * Avoid installed app UI runspace deadlock
This commit is contained in:
@@ -15,32 +15,36 @@ Function Invoke-WinUtilCurrentSystem {
|
||||
)
|
||||
if ($CheckBox -eq "choco") {
|
||||
$apps = (choco list | Select-String -Pattern "^\S+").Matches.Value
|
||||
$filter = Get-WinUtilVariables -Type Checkbox | Where-Object {$psitem -like "WPFInstall*"}
|
||||
$sync.GetEnumerator() | Where-Object {$psitem.Key -in $filter} | ForEach-Object {
|
||||
$dependencies = @($sync.configs.applications.$($psitem.Key).choco -split ";")
|
||||
if ($dependencies -in $apps) {
|
||||
Write-Output $psitem.name
|
||||
$sync.configs.applicationsHashtable.GetEnumerator() | ForEach-Object {
|
||||
$packageId = ($_.Value.choco -split ";")[-1].Trim()
|
||||
if ($packageId -ne "na" -and $packageId -in $apps) {
|
||||
Write-Output $_.Key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($checkbox -eq "winget") {
|
||||
|
||||
$originalEncoding = [Console]::OutputEncoding
|
||||
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
|
||||
$Sync.InstalledPrograms = @("winget", "msstore") | ForEach-Object {
|
||||
winget list -s $psitem | Select-Object -skip 3 | ConvertFrom-String -PropertyNames "Name", "Id", "Version", "Available" -Delimiter '\s{2,}'
|
||||
try {
|
||||
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
|
||||
$installedProgramOutput = @(winget list --accept-source-agreements --disable-interactivity 2>&1)
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "winget list failed with exit code $LASTEXITCODE."
|
||||
}
|
||||
} finally {
|
||||
[Console]::OutputEncoding = $originalEncoding
|
||||
}
|
||||
[Console]::OutputEncoding = $originalEncoding
|
||||
$installedProgramText = $installedProgramOutput -join "`n"
|
||||
|
||||
$filter = Get-WinUtilVariables -Type Checkbox | Where-Object {$psitem -like "WPFInstall*"}
|
||||
$sync.GetEnumerator() | Where-Object {$psitem.Key -in $filter} | ForEach-Object {
|
||||
$dependencies = @($sync.configs.applications.$($psitem.Key).winget -split ";") | ForEach-Object {
|
||||
$psitem -replace "^msstore:", ""
|
||||
$sync.configs.applicationsHashtable.GetEnumerator() | ForEach-Object {
|
||||
$packageId = (($_.Value.winget -split ";")[-1] -replace "^msstore:", "").Trim()
|
||||
if ([string]::IsNullOrWhiteSpace($packageId) -or $packageId -eq "na") {
|
||||
return
|
||||
}
|
||||
|
||||
if ($dependencies[-1] -in $sync.InstalledPrograms.Id) {
|
||||
Write-Output $psitem.name
|
||||
$packagePattern = "(?im)[^\S\r\n]{2,}$([regex]::Escape($packageId))(?=[^\S\r\n]{2,}|$)"
|
||||
if ($installedProgramText -match $packagePattern) {
|
||||
Write-Output $_.Key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
function Invoke-WPFGetInstalled {
|
||||
<#
|
||||
TODO: Add the Option to use Chocolatey as Engine
|
||||
.SYNOPSIS
|
||||
Invokes the function that gets the checkboxes to check in a new runspace
|
||||
|
||||
@@ -19,35 +18,72 @@ function Invoke-WPFGetInstalled {
|
||||
return
|
||||
}
|
||||
$managerPreference = $sync.preferences.packagemanager
|
||||
|
||||
Invoke-WPFRunspace -ParameterList @(("managerPreference", $managerPreference),("checkbox", $checkbox)) -ScriptBlock {
|
||||
param (
|
||||
[string]$checkbox,
|
||||
[string]$managerPreference
|
||||
$operation = [Hashtable]::Synchronized(@{
|
||||
Checkboxes = @()
|
||||
Error = $null
|
||||
})
|
||||
$completeAction = [Action[hashtable, string]]{
|
||||
param(
|
||||
[hashtable]$completedOperation,
|
||||
[string]$completedCheckbox
|
||||
)
|
||||
$sync.ProcessRunning = $true
|
||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Indeterminate" }
|
||||
try {
|
||||
if ($completedOperation.Error) {
|
||||
Write-WinUtilLog -Level "ERROR" -Component "Install" -Message "Get installed state failed: $($completedOperation.Error)"
|
||||
Write-Warning "Unable to get installed state: $($completedOperation.Error)"
|
||||
return
|
||||
}
|
||||
|
||||
if ($checkbox -eq "winget") {
|
||||
Write-Host "Getting Installed Programs..."
|
||||
switch ($managerPreference) {
|
||||
"Choco"{$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox "choco"; break}
|
||||
"Winget"{$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox; break}
|
||||
if ($completedCheckbox -eq "winget") {
|
||||
foreach ($checkboxName in $completedOperation.Checkboxes) {
|
||||
if (-not $sync.selectedApps.Contains($checkboxName)) {
|
||||
$sync.selectedApps.Add($checkboxName)
|
||||
}
|
||||
}
|
||||
Reset-WPFCheckBoxes -checkboxfilterpattern "WPFInstall*"
|
||||
} else {
|
||||
foreach ($checkboxName in $completedOperation.Checkboxes) {
|
||||
$sync.$checkboxName.ischecked = $True
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
$sync.ProcessRunning = $false
|
||||
Set-WinUtilTaskbaritem -state "None"
|
||||
}
|
||||
}
|
||||
|
||||
$sync.ProcessRunning = $true
|
||||
Set-WinUtilTaskbaritem -state "Indeterminate"
|
||||
try {
|
||||
Invoke-WPFRunspace -ParameterList @(
|
||||
("managerPreference", $managerPreference),
|
||||
("checkbox", $checkbox),
|
||||
("operation", $operation),
|
||||
("completeAction", $completeAction)
|
||||
) -ScriptBlock {
|
||||
param (
|
||||
[string]$checkbox,
|
||||
[string]$managerPreference,
|
||||
[hashtable]$operation,
|
||||
[Action[hashtable, string]]$completeAction
|
||||
)
|
||||
try {
|
||||
if ($checkbox -eq "winget") {
|
||||
switch ($managerPreference) {
|
||||
"Choco" { $operation.Checkboxes = @(Invoke-WinUtilCurrentSystem -CheckBox "choco"); break }
|
||||
"Winget" { $operation.Checkboxes = @(Invoke-WinUtilCurrentSystem -CheckBox $checkbox); break }
|
||||
}
|
||||
} elseif ($checkbox -eq "tweaks") {
|
||||
$operation.Checkboxes = @(Invoke-WinUtilCurrentSystem -CheckBox $checkbox)
|
||||
}
|
||||
} catch {
|
||||
$operation.Error = $_.Exception.Message
|
||||
} finally {
|
||||
$sync.Form.Dispatcher.BeginInvoke($completeAction, [object[]]@($operation, $checkbox)) | Out-Null
|
||||
}
|
||||
}
|
||||
elseif ($checkbox -eq "tweaks") {
|
||||
Write-Host "Getting Installed Tweaks..."
|
||||
$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox
|
||||
}
|
||||
|
||||
$sync.form.Dispatcher.invoke({
|
||||
foreach ($checkbox in $Checkboxes) {
|
||||
$sync.$checkbox.ischecked = $True
|
||||
}
|
||||
})
|
||||
|
||||
Write-Host "Done..."
|
||||
$sync.ProcessRunning = $false
|
||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" }
|
||||
} catch {
|
||||
$operation.Error = $_.Exception.Message
|
||||
$completeAction.Invoke($operation, $checkbox)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ public sealed class WinUtilRunspaceCleanupState
|
||||
|
||||
public static class WinUtilRunspaceCleanup
|
||||
{
|
||||
public static readonly System.Threading.WaitOrTimerCallback Callback = Cleanup;
|
||||
|
||||
public static void Cleanup(object state, bool timedOut)
|
||||
{
|
||||
var cleanupState = state as WinUtilRunspaceCleanupState;
|
||||
@@ -89,8 +91,7 @@ public static class WinUtilRunspaceCleanup
|
||||
$cleanupState = [WinUtilRunspaceCleanupState]::new()
|
||||
$cleanupState.PowerShell = $powershell
|
||||
$cleanupState.Handle = $handle
|
||||
$cleanupCallback = [System.Threading.WaitOrTimerCallback][WinUtilRunspaceCleanup]::Cleanup
|
||||
[System.Threading.ThreadPool]::RegisterWaitForSingleObject($handle.AsyncWaitHandle, $cleanupCallback, $cleanupState, -1, $true) | Out-Null
|
||||
[System.Threading.ThreadPool]::RegisterWaitForSingleObject($handle.AsyncWaitHandle, [WinUtilRunspaceCleanup]::Callback, $cleanupState, -1, $true) | Out-Null
|
||||
|
||||
# Return the handle
|
||||
return $handle
|
||||
|
||||
@@ -7,11 +7,21 @@ function Invoke-WPFSelectedCheckboxesUpdate ($type, $checkboxName) {
|
||||
'^WPFAppx' { 'selectedAppx' }
|
||||
}
|
||||
|
||||
$selectionChanged = $false
|
||||
if ($type -eq "Add") {
|
||||
if (-not $sync.$listName.Contains($checkboxName)) {
|
||||
$sync.$listName.Add($checkboxName)
|
||||
$selectionChanged = $true
|
||||
}
|
||||
} else {
|
||||
$sync.$listName.Remove($checkboxName)
|
||||
$selectionChanged = $sync.$listName.Remove($checkboxName)
|
||||
}
|
||||
|
||||
if ($listName -eq "selectedApps" -and $selectionChanged) {
|
||||
$sync.WPFselectedAppsButton.Content = "Selected Apps: $($sync.selectedApps.Count)"
|
||||
$sync.selectedAppsstackPanel.Children.Clear()
|
||||
$sync.selectedApps | Sort-Object | ForEach-Object {
|
||||
Add-SelectedAppsMenuItem -name $sync.configs.applicationsHashtable.$_.Content -key $_
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user