6

This may be a question that is difficult to answer. I wrote a Script that checks the responding property of a process. to visualize that the script is running, i created a windows form where you can see which process is watched. The script runs perfectly, but I can't do anything with my winform. Can't minimize or close it, my mouse cursor switches to the hourglass symbol as soon as I move the cursor to the windowsform. any ideas why?

The winform is also not responding when I comment out the while loop

here's my code:

if ($ShowWindowsForm){
    $window = New-Object System.Windows.Forms.Form
    $window.text = "Process Watcher"
    $window.size = New-Object System.Drawing.Size(350,100) 
    $window.location = New-Object System.Drawing.Size(100,100) 
    $icon = [system.drawing.icon]::ExtractAssociatedIcon($PSHOME + "\powershell.exe")
    $window.Icon = $Icon
    $text = New-Object System.Windows.Forms.Label
    $text.Text = "Folgender Prozess wird überwacht:`n$target.exe"
    $text.location = New-Object System.Drawing.Size(10,10) 
    $text.AutoSize = $true
    $window.Controls.Add($text)
    $window.Show()
}
while (1) {
    sleep -Milliseconds 100
    if(!((get-process $target).Responding -eq $true)) {
    #do stuff
}
SimonS
  • 1,891
  • 1
  • 29
  • 53
  • 2
    http://stackoverflow.com/questions/10794455/powershell-freezing-gui – David Brabant Feb 08 '16 at 10:54
  • thx, flagged my question as duplicate – SimonS Feb 08 '16 at 10:54
  • 7
    Simple to answer, actually: only one thing can happen at a time on a single thread. You are running a loop on the UI thread, which blocks any UI stuff from happening at the same time. Which means that your application goes stupid (becomes unresponsive). The solution is to do all of your processing on a background thread. Not sure if Powershell has something like that built in. If not, then you should be doing this in a language designed for GUI programming, like C# or VB.NET. Note that the linked question may be a duplicate, but the answer is *terrible* advice. – Cody Gray - on strike Feb 08 '16 at 10:56

1 Answers1

6

I got the answer now, if anyone runs into the same problem as I have.

First of all, if you just create a GUI and do some processing, they use the same thread. example:

# Windows Form    
$window = New-Object System.Windows.Forms.Form
$window.text = "Process Watcher"
$window.size = New-Object System.Drawing.Size(350,100) 
$window.location = New-Object System.Drawing.Size(100,100) 
$window.ShowDialog()

# Processing
while (1) { # Do Stuff }

PowerShell will now show the $window because of the .ShowDialog() method, but the Windows Form ($window) won't be responsive. That's because you're running a loop in the same thread as you show the Windows-Form Dialog.

So we need to create a Background Task for the loop, so it has a thread for itself. That's what PowerShell's Start-Job cmdlet is for.

let's say you're monitoring a process, and want to visualize it in a Windows-Form. Your Code will look like this:

$target = "firefox"

# Job
Start-Job -argumentlist $target {
    param($target)
    while ((get-process $target).Responding) {Sleep -Milliseconds 100}
    if (!(get-process $target).Responding) {<# Do Stuff #>}
}

# Windows Form    
$window = New-Object System.Windows.Forms.Form
$window.text = "Process Watcher"
$window.size = New-Object System.Drawing.Size(350,100) 
$window.location = New-Object System.Drawing.Size(100,100) 
$window.ShowDialog()

with this code, your Windows-Form is responsible, and your loop is executing in the background. What i also want to show with this code example is, that you have to pass a variable which you declared outside the job scriptblock to the job with the -argumentlist Parameter and param() statement. otherwise it won't work.

I hope this answer will help someone because google doesn't really give a good answer to this (or I just didn't find a good one)

SimonS
  • 1,891
  • 1
  • 29
  • 53
  • Note that it is `.Show()`, as in your question, that causes the non-responsive GUI; by contrast `.ShowDialog()` guarantees responsiveness, but *blocks* until the form is closed. – mklement0 Sep 06 '21 at 14:35