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)
几年后(代码不再在我面前),我将为遇到此问题的其他人添加答案。
事实证明,问题正如汉斯·帕桑特所猜测的那样。问题是,由于 .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)
此解决方案以及对问题原因的极其深入的研究可在此处找到。