Program hangs after leaving screen saver or lockin

2020-06-13 06:13发布

Our program works fine, until someone locks the computer or the screen-saver pops up (but not ctrl+alt+delete). Once the computer is unlocked/the screen saver is closed, the application stops drawing everything except the title bar, and stops responding to input - it displays a mostly-white window which can't be moved or closed.

Example of application freezing

(Example of application freezing - the mountains are from my desktop background)

If we let it sit for about 5~10 minutes, it comes back to life, and doesn't hang again (even after locking the computer/screen saver popup) until the application is restarted.

It's difficult to debug, because it doesn't happen when the program is started from Visual Studio, only when the .exe is manually opened.

It only happens when the splash-screen is shown - if I remove the code to show the splash-screen, it stops happening. We need the splash-screen, however.

I've tried every suggestion on this page; the only one this doesn't happen with is using Microsoft.VisualBasic.WindowsFormsApplicationBase, but that causes all sorts of other problems.

Information about this on the Internet appears to be scarce - has anyone run into a similar problem before?


Here is the relevant code:

//Multiple programs use this login form, all have the same issue
public partial class LoginForm<TMainForm>
    where TMainForm : Form, new()
{
    private readonly Action _showLoadingForm;

    public LoginForm(Action showLoadingForm)
    {
        ...
        _showLoadingForm = showLoadingForm;
    }

    private void btnLogin_Click(object sender, EventArgs e)
    {
        ...
        this.Hide();
        ShowLoadingForm(); //Problem goes away when commenting-out this line
        new TMainForm().ShowDialog();
        this.Close();
    }

    private void ShowLoadingForm()
    {
        Thread loadingFormThread = new Thread(o => _showLoadingForm());
        loadingFormThread.IsBackground = true;
        loadingFormThread.SetApartmentState(ApartmentState.STA);
        loadingFormThread.Start();
    }
}

Here is an example of one of the _showLoadingForm actions used in one of the programs:

public static bool _showSplash = true;
public static void ShowSplashScreen()
{
    //Ick, DoEvents!  But we were having problems with CloseSplashScreen being called
    //before ShowSplashScreen - this hack was found at
    //https://stackoverflow.com/questions/48916/multi-threaded-splash-screen-in-c/48946#48946
    using(SplashForm splashForm = new SplashForm())
    {
        splashForm.Show();
        while(_showSplash)
            Application.DoEvents();
        splashForm.Close();
    }
}

//Called in MainForm_Load()
public static void CloseSplashScreen()
{
    _showSplash = false;
}

10条回答
够拽才男人
2楼-- · 2020-06-13 06:43

I think your problem is because you are using Form.ShowDialog, not Application.Run. ShowDialog runs a restricted message loop that runs on top of the main message loop and ignores some windows messages.

Something like this should work:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault( false );

        Application.Run( new MainForm() );
    }
}


public partial class MainForm: Form
{
    FormSplash dlg = null;

    void ShowSplashScreen()
    {
        var t = new Thread( () =>
            {
                using ( dlg = new FormSplash() ) dlg.ShowDialog();
            }
        );

        t.SetApartmentState( ApartmentState.STA );
        t.IsBackground = true;
        t.Start();
    }

    void CloseSplashScreen()
    {
        dlg.Invoke( ( MethodInvoker ) ( () => dlg.Close() ) );
    }

    public MainForm()
    {
        ShowSplashScreen();

        InitializeComponent();

        Thread.Sleep( 3000 ); // simulate big form

        CloseSplashScreen();
    }
}
查看更多
冷血范
3楼-- · 2020-06-13 06:44

From the quick scan I did of your code, it looks like the key to your problem might be using

Application.Run(_splashForm);

Ideally you would use that inside a thread, but maybe it would work in conjunction with your DoEvents too. Sorry if you are doing that and I just missed it...

查看更多
对你真心纯属浪费
4楼-- · 2020-06-13 06:44

Here's a shot in the dark: when we idle, we also ask the thread to go to sleep. I'm not sure that this will help, but it's worth a shot:

    while(_showSplash) {
        System.Threading.Thread.Sleep(500);
        Application.DoEvents();
    }
查看更多
▲ chillily
5楼-- · 2020-06-13 06:50

since there is no working example

can you try removing Application.DoEvents(); and inserting a thread.sleep?

Application.DoEvents(); let say can be very evil.

查看更多
登录 后发表回答