fix gui install runspace
All checks were successful
Release / build-release (push) Successful in 5s

This commit is contained in:
Ludwig Lehnert
2026-07-01 12:18:59 +00:00
parent 91208323ab
commit 3039562e91
2 changed files with 202 additions and 40 deletions

2
dist/setup.ps1 vendored

File diff suppressed because one or more lines are too long

240
setup.ps1
View File

@@ -1494,6 +1494,140 @@ function Load-AppList {
`$stateRefreshTimer.Interval = 500 `$stateRefreshTimer.Interval = 500
`$script:StateRefreshPending = `$false `$script:StateRefreshPending = `$false
`$script:RequestWorkerBusy = `$false `$script:RequestWorkerBusy = `$false
`$script:RunspaceJobs = New-Object 'System.Collections.Generic.List[object]'
function Start-CatalogDaemonRunspaceRequest {
param(
[Parameter(Mandatory=`$true)][string]`$Command,
[string]`$Alias,
`$Context,
[Parameter(Mandatory=`$true)][scriptblock]`$OnCompleted
)
`$runspace = [runspacefactory]::CreateRunspace()
`$powershell = [powershell]::Create()
`$timer = New-Object System.Windows.Forms.Timer
`$timer.Interval = 100
`$job = [pscustomobject]@{
PowerShell = `$powershell
Runspace = `$runspace
AsyncResult = `$null
Timer = `$timer
Context = `$Context
OnCompleted = `$OnCompleted
}
try {
`$runspace.ApartmentState = 'MTA'
`$runspace.ThreadOptions = 'ReuseThread'
`$runspace.Open()
`$runspace.SessionStateProxy.SetVariable('PipeName', `$PipeName)
`$runspace.SessionStateProxy.SetVariable('Command', `$Command)
`$runspace.SessionStateProxy.SetVariable('Alias', `$Alias)
`$powershell.Runspace = `$runspace
[void]`$powershell.AddScript({
Set-StrictMode -Version Latest
`$ErrorActionPreference = 'Stop'
`$payload = [ordered]@{
Command = `$Command
AppAlias = `$Alias
}
`$json = `$payload | ConvertTo-Json -Compress
`$encoding = New-Object System.Text.UTF8Encoding(`$false)
`$client = New-Object System.IO.Pipes.NamedPipeClientStream -ArgumentList @(
'.',
`$PipeName,
[System.IO.Pipes.PipeDirection]::InOut,
[System.IO.Pipes.PipeOptions]::None,
[System.Security.Principal.TokenImpersonationLevel]::Impersonation
)
try {
`$client.Connect(10000)
`$reader = New-Object System.IO.StreamReader(`$client, `$encoding)
`$writer = New-Object System.IO.StreamWriter(`$client, `$encoding)
`$writer.AutoFlush = `$true
`$writer.WriteLine(`$json)
`$readTask = `$reader.ReadLineAsync()
if (-not `$readTask.Wait(15000)) {
throw 'Zeitüberschreitung beim Warten auf Antwort des Softwarekatalog-Dienstes.'
}
`$line = `$readTask.Result
if ([string]::IsNullOrWhiteSpace(`$line)) {
throw 'Der Softwarekatalog-Dienst hat keine Antwort gesendet.'
}
`$response = `$line | ConvertFrom-Json
if (-not `$response.Success) {
throw ([string]`$response.Message)
}
return `$response
}
catch [System.TimeoutException] {
throw 'Der Softwarekatalog-Dienst ist nicht erreichbar oder startet noch. Bitte versuchen Sie es erneut.'
}
finally {
`$client.Dispose()
}
}.ToString())
`$job.AsyncResult = `$powershell.BeginInvoke()
}
catch {
`$timer.Dispose()
`$powershell.Dispose()
`$runspace.Dispose()
throw
}
[void]`$script:RunspaceJobs.Add(`$job)
`$timer.Add_Tick({
if (-not `$job.AsyncResult.IsCompleted) { return }
`$job.Timer.Stop()
`$completion = [pscustomobject]@{
Context = `$job.Context
Response = `$null
ErrorMessage = `$null
}
try {
`$result = @(`$job.PowerShell.EndInvoke(`$job.AsyncResult))
if (`$job.PowerShell.Streams.Error.Count -gt 0) {
`$firstError = `$job.PowerShell.Streams.Error[0]
if (`$firstError.Exception) {
`$completion.ErrorMessage = `$firstError.Exception.Message
}
else {
`$completion.ErrorMessage = [string]`$firstError
}
}
elseif (`$result.Count -gt 0) {
`$completion.Response = `$result[-1]
}
}
catch {
`$completion.ErrorMessage = `$_.Exception.Message
}
try {
& `$job.OnCompleted `$completion
}
finally {
[void]`$script:RunspaceJobs.Remove(`$job)
`$job.Timer.Dispose()
`$job.PowerShell.Dispose()
`$job.Runspace.Dispose()
}
})
`$timer.Start()
}
function Start-AppRequestAsync { function Start-AppRequestAsync {
param( param(
@@ -1511,29 +1645,24 @@ function Start-AppRequestAsync {
`$btnUninstall.Enabled = `$false `$btnUninstall.Enabled = `$false
`$btnRefresh.Enabled = `$false `$btnRefresh.Enabled = `$false
`$worker = New-Object System.ComponentModel.BackgroundWorker `$context = [pscustomobject]@{
`$worker.Add_DoWork({ Action = `$Action
param(`$sender, `$eventArgs) Alias = [string]`$Selected.Alias
`$arg = `$eventArgs.Argument DisplayName = [string]`$Selected.DisplayName
`$response = New-AppRequest -Alias `$arg.Alias -Action `$arg.Action }
`$eventArgs.Result = [pscustomobject]@{
Action = `$arg.Action try {
Alias = `$arg.Alias Start-CatalogDaemonRunspaceRequest -Command `$Action -Alias `$context.Alias -Context `$context -OnCompleted {
DisplayName = `$arg.DisplayName param(`$completion)
Response = `$response
}
})
`$worker.Add_RunWorkerCompleted({
param(`$sender, `$eventArgs)
try { try {
`$script:RequestWorkerBusy = `$false `$script:RequestWorkerBusy = `$false
`$btnRefresh.Enabled = `$true `$btnRefresh.Enabled = `$true
if (`$eventArgs.Error) { if (`$completion.ErrorMessage) {
`$status.Text = 'Fehler: ' + `$eventArgs.Error.Message `$status.Text = 'Fehler: ' + `$completion.ErrorMessage
`$script:StateRefreshPending = `$true `$script:StateRefreshPending = `$true
[System.Windows.Forms.MessageBox]::Show( [System.Windows.Forms.MessageBox]::Show(
`$eventArgs.Error.Message, `$completion.ErrorMessage,
`$CatalogTitle, `$CatalogTitle,
[System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxButtons]::OK,
[System.Windows.Forms.MessageBoxIcon]::Error [System.Windows.Forms.MessageBoxIcon]::Error
@@ -1541,7 +1670,12 @@ function Start-AppRequestAsync {
return return
} }
`$result = `$eventArgs.Result `$result = [pscustomobject]@{
Action = `$completion.Context.Action
Alias = `$completion.Context.Alias
DisplayName = `$completion.Context.DisplayName
Response = `$completion.Response
}
if (`$result.Action -eq 'Uninstall') { if (`$result.Action -eq 'Uninstall') {
`$verb = 'Deinstallation' `$verb = 'Deinstallation'
} }
@@ -1566,14 +1700,15 @@ function Start-AppRequestAsync {
} }
finally { finally {
Update-InstallButtonState Update-InstallButtonState
`$sender.Dispose()
} }
}) }
`$worker.RunWorkerAsync([pscustomobject]@{ }
Action = `$Action catch {
Alias = [string]`$Selected.Alias `$script:RequestWorkerBusy = `$false
DisplayName = [string]`$Selected.DisplayName `$btnRefresh.Enabled = `$true
}) Update-InstallButtonState
throw
}
} }
function Start-RefreshStatusAsync { function Start-RefreshStatusAsync {
@@ -1588,21 +1723,17 @@ function Start-RefreshStatusAsync {
`$btnRefresh.Enabled = `$false `$btnRefresh.Enabled = `$false
`$status.Text = 'Installationsdaten-Aktualisierung wird angefordert...' `$status.Text = 'Installationsdaten-Aktualisierung wird angefordert...'
`$worker = New-Object System.ComponentModel.BackgroundWorker try {
`$worker.Add_DoWork({ Start-CatalogDaemonRunspaceRequest -Command 'RefreshStatus' -OnCompleted {
param(`$sender, `$eventArgs) param(`$completion)
`$eventArgs.Result = Invoke-CatalogDaemon -Command 'RefreshStatus'
})
`$worker.Add_RunWorkerCompleted({
param(`$sender, `$eventArgs)
try { try {
`$script:RequestWorkerBusy = `$false `$script:RequestWorkerBusy = `$false
`$btnRefresh.Enabled = `$true `$btnRefresh.Enabled = `$true
if (`$eventArgs.Error) { if (`$completion.ErrorMessage) {
`$status.Text = 'Fehler: ' + `$eventArgs.Error.Message `$status.Text = 'Fehler: ' + `$completion.ErrorMessage
[System.Windows.Forms.MessageBox]::Show( [System.Windows.Forms.MessageBox]::Show(
`$eventArgs.Error.Message, `$completion.ErrorMessage,
`$CatalogTitle, `$CatalogTitle,
[System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxButtons]::OK,
[System.Windows.Forms.MessageBoxIcon]::Error [System.Windows.Forms.MessageBoxIcon]::Error
@@ -1610,16 +1741,21 @@ function Start-RefreshStatusAsync {
return return
} }
`$response = `$eventArgs.Result `$response = `$completion.Response
if (`$response.Message) { `$status.Text = [string]`$response.Message } if (`$response.Message) { `$status.Text = [string]`$response.Message }
`$script:StateRefreshPending = `$true `$script:StateRefreshPending = `$true
} }
finally { finally {
Update-InstallButtonState Update-InstallButtonState
`$sender.Dispose()
} }
}) }
`$worker.RunWorkerAsync() }
catch {
`$script:RequestWorkerBusy = `$false
`$btnRefresh.Enabled = `$true
Update-InstallButtonState
throw
}
} }
`$btnInstall.Add_Click({ `$btnInstall.Add_Click({
@@ -1799,6 +1935,32 @@ function Start-RefreshStatusAsync {
`$stateRefreshTimer.Dispose() `$stateRefreshTimer.Dispose()
if (`$script:StateWatcher) { `$script:StateWatcher.Dispose() } if (`$script:StateWatcher) { `$script:StateWatcher.Dispose() }
if (`$script:SnapshotWatcher) { `$script:SnapshotWatcher.Dispose() } if (`$script:SnapshotWatcher) { `$script:SnapshotWatcher.Dispose() }
foreach (`$job in @(`$script:RunspaceJobs)) {
try {
if (`$job.Timer) {
`$job.Timer.Stop()
`$job.Timer.Dispose()
}
}
catch {
}
try {
if (`$job.PowerShell -and `$job.AsyncResult -and -not `$job.AsyncResult.IsCompleted) {
`$job.PowerShell.Stop()
}
}
catch {
}
try {
if (`$job.PowerShell) { `$job.PowerShell.Dispose() }
if (`$job.Runspace) { `$job.Runspace.Dispose() }
}
catch {
}
}
`$script:RunspaceJobs.Clear()
}) })
`$list.Add_SelectedIndexChanged({ Update-InstallButtonState }) `$list.Add_SelectedIndexChanged({ Update-InstallButtonState })