离开屏幕保护程序或锁定计算机后程序挂起

Blu*_*eft 10 c# vb.net multithreading hang winforms

我们的程序工作正常,直到有人锁定计算机或屏幕保护程序弹出(但不是ctrl + alt + delete).一旦计算机解锁/屏幕保护程序关闭,应用程序将停止绘制除标题栏以外的所有内容,并停止响应输入 - 它显示一个无法移动或关闭的大部分白色窗口.

应用程序冻结的示例

(应用程序冻结示例 - 山脉来自我的桌面背景)

如果我们让它静置大约5到10分钟,它会恢复生命,并且不会再次挂起(即使在锁定计算机/屏幕保护程序弹出窗口之后),直到应用程序重新启动.

调试很困难,因为只有在手动打开.exe时才从Visual Studio启动程序时才会发生这种情况.

它只在显示启动画面时发生 - 如果我删除代码以显示启动画面,它就会停止发生.但是,我们需要启动画面.

我已尝试过本页的所有建议 ; 唯一没有发生的是使用Microsoft.VisualBasic.WindowsFormsApplicationBase,但这会导致各种其他问题.

互联网上有关这方面的信息似乎很少 - 以前有没有人遇到过类似的问题?


这是相关代码:

//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();
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是其中_showLoadingForm一个程序中使用的其中一个操作的示例:

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;
}
Run Code Online (Sandbox Code Playgroud)

Blu*_*eft 1

几年后(代码不再在我面前),我将为遇到此问题的其他人添加答案。


事实证明,问题正如汉斯·帕桑特所猜测的那样。问题是,由于 .Net 框架中一些令人难以置信的模糊和无害的错误,有时会在应该返回时InvokeRequired返回,导致应该在 GUI 线程上运行的代码在后台运行(由于一些更模糊和无害的错误,导致了我所看到的行为)falsetrue

解决方案是不依赖InvokeRequired,使用类似于以下的 hack:

void Main()
{
    Thread.Current.Name = "GuiThread";
    ...
}

bool IsGuiThread()
{
    return Thread.Current.Name == "GuiThread";
}

//Later, call IsGuiThread() to determine if GUI code is being run on GUI thread
Run Code Online (Sandbox Code Playgroud)

此解决方案以及对问题原因的极其深入的研究可在此处找到。