question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Start-Sleep - unlike System.Threading.Thread.Sleep - in a WinForms DoEvents loop prevents reactivating a minimized window

See original GitHub issue

Prerequisites

Steps to reproduce

Note:

  • This is clearly not a common use case, but it would still be good to know the cause of the problem.
  • WPF windows are equally affected.
  • Using [System.Threading.Thread]::Sleep() in lieu of Start-Sleep makes the problem go away.
  • See below for additional details regarding what messages are missed.

Repro steps:

  • Run the following code, which shows a WinForms form non-modally and then uses a DoEvents() loop with periodic Start-Sleep calls to process GUI events until the form is closed:
Add-Type -AssemblyName System.Windows.Forms

# Create a sample form.
$form = [System.Windows.Forms.Form] @{
  Text = "Sample"; Size = [System.Drawing.Size]::new(600, 200); StartPosition = 'CenterScreen'
}

# Show the form *non-modally*
$null = $form.Show()

while ($form.Visible) {

  # Allow the form to process events.
  [System.Windows.Forms.Application]::DoEvents()

  # Sleep a little, to avoid a near-tight loop.
  # !! THIS CAUSES THE PROBLEM.
  # !! If you replace the Start-Sleep call with a call
  # !! to [System.Threading.Thread]::Sleep(), the problem goes away.
  Start-Sleep -Milliseconds 50

}
  • Minimize the form.

  • Hover over the PowerShell instance’s taskbar button and try to reactivate the form by clicking on its thumbnail.

Expected behavior

The form should be restored and activated.

Actual behavior

Nothing happens (while you hover, the form is previewed in its original position after a brief delay, but clicking the thumbnail is ineffective in restoring and activating it; clicking on the thumbnail’s close button does close the form).

Also, trying to Alt-Tab to the window doesn’t activate it either.

Error details

No response

Environment data

PowerShell 7.4.0-preview.3 on Windows 11 22H2

Visuals

No response

Issue Analytics

  • State:open
  • Created 3 months ago
  • Comments:6 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
fMichaleczekcommented, Jun 15, 2023

The Cmdlet Start-Sleep uses System.Threading.ManualResetEvent API instead of System.Threading.Thread.Sleep I can reproduce an issue between the method DoEvents and the ManualResetEvent class. It can also be resolved it by using a unique ManualResetEvent instance. (something that Start-Sleep is not doing I guess)

Not Working :

Add-Type -AssemblyName System.Windows.Forms
$form = [System.Windows.Forms.Form]@{
    Text = 'Sample'
    Size = [System.Drawing.Size]::new(600, 200)
    StartPosition = 'CenterScreen'
}
[void] $form.Show()
while ($form.Visible) {
    [void] [System.Windows.Forms.Application]::DoEvents()
    $waitHandle = [System.Threading.ManualResetEvent]::new(<# initialState: #> $false)
    [void] $waitHandle.WaitOne(<# millisecondsTimeout: #> 50, $true)
    [void] $waitHandle.Set()
    $waitHandle.Close()
}

Working :

Add-Type -AssemblyName System.Windows.Forms
$form = [System.Windows.Forms.Form]@{
    Text = 'Sample'
    Size = [System.Drawing.Size]::new(600, 200)
    StartPosition = 'CenterScreen'
}
[void] $form.Show()
$waitHandle = [System.Threading.ManualResetEvent]::new(<# initialState: #> $false)
while ($form.Visible) {
    [void] [System.Windows.Forms.Application]::DoEvents()
    [void] $waitHandle.WaitOne(<# millisecondsTimeout: #> 50, $true)
    [void] $waitHandle.Set()
} 
$waitHandle.Close()

Working :

Add-Type -AssemblyName System.Windows.Forms
$form = [System.Windows.Forms.Form]@{
    Text = 'Sample'
    Size = [System.Drawing.Size]::new(600, 200)
    StartPosition = 'CenterScreen'
}
[void] $form.Show()
while ($form.Visible) {
    [void] [System.Windows.Forms.Application]::DoEvents()
    if ($form.Focused) {
        $waitHandle = [System.Threading.ManualResetEvent]::new(<# initialState: #> $false)
        [void] $waitHandle.WaitOne(<# millisecondsTimeout: #> 50, $true)
        [void] $waitHandle.Set()
        $waitHandle.Close()
    }
}

Working :

Add-Type -AssemblyName System.Windows.Forms

$form = [System.Windows.Forms.Form]@{
    Text = 'Sample'
    Size = [System.Drawing.Size]::new(600, 200)
    StartPosition = 'CenterScreen'
}
[void] $form.Show()

while ($form.Visible) {
    [void] [System.Windows.Forms.Application]::DoEvents()
    $waitHandle = [System.Threading.ManualResetEvent]::new(<# initialState: #> $false)
    if ($form.WindowState -ne 'Minimized') {
        [void] $waitHandle.WaitOne(<# millisecondsTimeout: #> 50, $true)
    }
    [void] $waitHandle.Set()
    $waitHandle.Close()
}
1reaction
lippmajecommented, Jun 14, 2023

I can confirm this behavior for Windows 7 SP1, Powershell 5.1, .NET 4.8 (cannot test on newer OS right now). With Start-Sleep, the dialog misses the (WM_SYSCOMMAND, SC_MINIMIZE=0xF020) message that is sent if the taskbar icon is clicked while the dialog is open - likewise it misses the (WM_SYSCOMMAND, SC_RESTORE=0xF120) when the dialog was minimized, leaving it pretty inoperable in the taskbar. This does not happen when waiting with [Threading.Thread]::Sleep(20).

I also want to note that this behavior is independent from running the Winforms event handler or a WPF pendant.

Read more comments on GitHub >

github_iconTop Results From Across the Web

in a WinForms DoEvents loop prevents reactivating ...
Start-Sleep - unlike System.Threading.Thread.Sleep - in a WinForms DoEvents loop prevents reactivating a minimized window #23367. Sign in to view logs.
Read more >
In c# winforms application, why doesn't this sleep in a while ...
Just a suggestion - use Microsoft's Reactive Framework (Rx) - NuGet System.Reactive.Windows.Forms and pop a using System.Reative.
Read more >
Powershell GUI Freezing, even with runspace - wpf
A custom DoEvents() -like function, DoWpfEvents , adapted from the DispatcherFrame documentation is called in each loop operation for GUI event ...
Read more >
Thread.Sleep Method (System.Threading)
Suspends the current thread for the specified amount of time. ... The following example uses the Sleep method to block the application's main...
Read more >
Form stuck in minimized state while loop running?
That loop runs indefinitly and since i'm calling DoEvents at every iteration, the form stays responsive and i'm able to do anything with...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found