Why does putting [STAThread] on Program.Main in XNA game with slow FPS prevents restoring on minimize?

699 views Asked by At

The symptom I'm trying to resolve is that my XNA application will not restore some of the time after being being minimized. I click the minimize button, but when I click on my application's entry in the task bar, the application does not resume - it stays minimized. Furthermore, I hear a Windows "ding" sound effect play.

If I click on the application repeatedly it sometimes resumes. I've found that if my application has less processing time in its every-frame Update call, then the problem is harder to reproduce. If I add this:

 System.Threading.Thread.Sleep(100);

then it's almost impossible to have the application resume.

I've found that if I remove [STAThread] on Program.Main, it always resumes perfectly; however, I use winforms OpenFileDialog's which require STAThread to be set on the Main method so I can't get rid of that attribute.

Any thoughts as to why this might be happening, and if there's a way to both use STAThread and have the application properly resume?

Edit: Internally my application is using ThreadPool.QueueUserWorkItem, and the presence of that is what is causing this. Does this mean that ThreadPool.QueueUserWorkItem should not be used in a STAThread application?

2

There are 2 answers

0
Steve Lillis On

Do you mean STAThreadAttribute? If not, put that on on the main method instead.

I use STAThreadAttribute and ThreadPool.QueueUserWorkItem and do not have this issue. Note that Sleep() is specifically stopping the window from responding because it blocks the thread. Ideally you shouldn't be using sleep on your main thread for the game.

0
James Plotts On

I used a different method to get around this. To keep my dialogs and forms from blocking the main thread, I place my code in a separate subroutine and start a new thread:

Protected Overrides Sub Update(gametime As GameTime)
    ...
    If (Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.O)) Then ' load a new object
         If loadthreadrunning = False Then
             loadthreadrunning = True
             Dim thread As New Thread(AddressOf BackgroundLoader)
             thread.SetApartmentState(ApartmentState.STA)
             thread.Start()
         End If
    End If
    ...
End Sub

...
Sub BackgroundLoader()
    Dim fd As New OpenFileDialog
    Dim dlgres As DialogResult
    dlgres = fd.ShowDialog()
    ...
    loadthreadrunning = False
End Sub 

Of course, my code is in VB, but the same technique will work for C#.