【发布时间】:2011-12-29 19:00:52
【问题描述】:
我们的程序运行良好,直到有人锁定计算机或弹出屏幕保护程序(但不是 ctrl+alt+delete)。一旦计算机解锁/屏幕保护程序关闭,应用程序将停止绘制除标题栏以外的所有内容,并停止响应输入 - 它显示一个无法移动或关闭的大部分白色窗口。
(应用程序冻结示例 - 山脉来自我的桌面背景)
如果我们让它静置大约 5~10 分钟,它就会恢复活力,并且不会再次挂起(即使在锁定计算机/屏幕保护程序弹出窗口之后),直到应用程序重新启动.
很难调试,因为从Visual Studio启动程序时不会发生,只有手动打开.exe时才会发生。
只有在启动画面显示时才会发生 - 如果我删除代码以显示启动画面,它就会停止发生。但是,我们需要启动画面。
我已经尝试了this page的所有建议;唯一不会发生这种情况的是使用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();
}
}
以下是其中一个程序中使用的_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;
}
【问题讨论】:
-
调试器锁定时能不能附加?
-
仔细看看它挂在哪里。是真的在
MainForm.ShowDialog内部,还是在调用堆栈中更具体的东西。如果它真的被困在ShowDialog中,那么这意味着消息不再被泵送到主 UI 线程上。这将是非常奇怪的,并且可能表明 .NET 中存在一个仅在显示初始屏幕时才会出现的模糊错误。这是一个很奇怪的问题。 -
顺便说一下,调用
Application.DoEvents的while 循环应该会不停地旋转。是否消耗大量 CPU 时间? -
和
_showSplash应该是volatile,顺便说一句。 -
如果你没有看到它没有任何意义。这种代码经常会遇到 SystemEvents 类的问题。你可以混淆它,让它在错误的线程上触发事件。
标签: c# vb.net winforms multithreading freeze