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

2023-12-19

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

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

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

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

仅当显示启动屏幕时才会发生- 如果我删除代码以显示启动屏幕,它就会停止发生。然而,我们需要启动画面。

我已经尝试了所有建议这一页 https://stackoverflow.com/questions/48916/multi-threaded-splash-screen-in-c;唯一不会发生这种情况的是使用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;
}

启动画面问题

DoEvents 的事情是非常不可取的,并且不一定能实现您认为它所做的事情。 DoEvents 告诉 CLR 关注 Windows 消息循环(用于启动屏幕),但不一定为其他线程提供任何处理时间。Thread.Sleep()将为其他线程提供处理的机会,但不一定允许启动屏幕的 Windows 消息循环继续发送消息。因此,如果您必须使用循环,那么您确实需要两者,但稍后我将建议完全摆脱此循环。除了循环问题之外,我没有看到任何明确的方式来清理启动线程。你需要某种Thread.Join() or Thread.Abort()发生在某处。

而不是使用Application.DoEvents()循环中,我喜欢使用 ManualResetEvent 来同步启动窗体与调用线程的启动。这样,ShowSplash() 方法在显示启动画面之前不会返回。此后的任何时候,我们显然都可以关闭它,因为我们知道它已经完成了展示。

这是一个包含一些很好示例的线程:C# 中的 .NET 多线程启动屏幕 https://stackoverflow.com/questions/48916/multi-threaded-splash-screen-in-c

下面是我如何修改我最喜欢的示例(@AdamNosfinger 发布的),以包含 ManualResetEvent,以将 ShowSplash 方法与闪屏线程同步:

public partial class FormSplash : Form
{
    private static Thread _splashThread;
    private static FormSplash _splashForm;
    // This is used to make sure you can't call SplashScreenClose before the SplashScreenOpen has finished showing the splash initially.
    static ManualResetEvent SplashScreenLoaded;

    public FormSplash()
    {
        InitializeComponent();

        // Signal out ManualResetEvent so we know the Splash form is good to go.
        SplashScreenLoaded.Set();
    }

    /// <summary>
    /// Show the Splash Screen (Loading...)
    /// </summary>
    public static void ShowSplash()
    {
        if (_splashThread == null)
        {
            // Setup our manual reset event to syncronize the splash screen thread and our main application thread.
            SplashScreenLoaded = new ManualResetEvent(false);

            // show the form in a new thread
            _splashThread = new Thread(new ThreadStart(DoShowSplash));
            _splashThread.IsBackground = true;
            _splashThread.Start();

            // Wait for the splash screen thread to let us know its ok for the app to keep going. 
            // This next line will not return until the SplashScreen is loaded.
            SplashScreenLoaded.WaitOne();
            SplashScreenLoaded.Close();
            SplashScreenLoaded = null;
        }
    }

    // called by the thread
    private static void DoShowSplash()
    {
        if (_splashForm == null)
            _splashForm = new FormSplash();

        // create a new message pump on this thread (started from ShowSplash)
        Application.Run(_splashForm);
    }

    /// <summary>
    /// Close the splash (Loading...) screen
    /// </summary>
    public static void CloseSplash()
    {
        // need to call on the thread that launched this splash
        if (_splashForm.InvokeRequired)
            _splashForm.Invoke(new MethodInvoker(CloseSplash));

        else
            Application.ExitThread();
    }
}

主要表格问题

看起来好像您正在使用 ShowDialog 从登录窗口启动主窗体,然后关闭登录窗体。我理解正确吗?如果这样的话就不好了。 ShowDialog 适用于应用程序的子窗口,并且希望有一个所有者窗口,如果您没有在方法参数中指定所有者表单,则当前活动窗口被假定为所有者。看MSDN http://msdn.microsoft.com/en-us/library/c7ykbedk.aspx

因此,您的主表单假设登录表单是其父表单,但您在显示主表单后不久就关闭了登录表单。所以我不确定应用程序此时处于什么状态。您应该考虑使用标准Form.Show()方法,如果这是所需的结果,只需调整 Form 属性以显示为对话框(例如:BorderStyle、MaximizeBox、MinimizeBox、ControlBox、TopMost)。

重要编辑:好吧,我是人,我搞砸了,忘记了 ShowDialog 是一个阻塞方法。虽然这确实否定了所有者句柄问题,但我仍然建议不要在主应用程序表单中使用 ShowDialog,除非您可以提供与外观或线程无关的重要理由(因为这些应该通过其他技术来修复)。尽管我犯了错误,但这个建议仍然是合理的。

可能的绘画问题

您没有指定您正在使用哪些控件,也没有指定您是否在应用程序中进行任何自定义绘制。但您需要记住,当您锁定计算机时,某些窗口句柄将被强制关闭。例如,如果您有一些自定义绘制的控件并且正在缓存字体、画笔或其他 GDI 资源,您需要有一些try { ... } catch { ... }当绘制期间引发异常时,代码中的块会处理然后重建缓存的 GDI 资源。我之前在自定义绘制列表框并缓存一些 GDI 对象时遇到过这种情况。如果您的应用程序中的任何位置(包括启动屏幕中)有任何自定义绘制代码,请仔细检查所有 GDI 对象是否已妥善处理/清理。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

离开屏幕保护程序或锁定计算机后程序挂起 的相关文章

随机推荐

  • 如何使用 Qt 禁用 Alt + F4 窗口关闭?

    我使用以下行从对话框中禁用了 Qt 中的 X 按钮 myDialog gt setWindowFlags Qt Dialog Qt Desktop but I couldn t detect Alt F4 using this code v
  • 在 ember js 和 mvc 中使用验证码

    我正在使用创建一个网站ember js and asp net mvc 在我之前的asp net我用过的网站captchaMVC http captchamvc codeplex com http captchamvc codeplex c
  • 无奈地迷失了 openCV 和 HoughCircles

    我正在尝试检测这个黑色圆圈here https i stack imgur com clpR6 png 应该不会太困难 但由于某种原因 我到处都是 0 个圆圈或大约 500 个圆圈 具体取决于参数 但没有中间立场 感觉就像我已经尝试了几个小
  • 以编程方式一步提取 tar.gz(在使用 7-Zip 的 Windows 上)

    Problem 我希望能够一步提取 tar gz 文件 这让我的问题almost与此相同 tar gz 的堆栈溢出问题 https stackoverflow com questions 651018 opening a tar gz fi
  • scala 的鼠标事件有效吗?如何?

    我正在尝试在 scala 中创建类似链接的标签 但没有鼠标事件对我有用 他们应该如何工作 class Hyperlink extends Label text hyperlink reactions case MouseClicked gt
  • 如果我不关闭 StardandInput,C# 重定向其他控制台应用程序 StandardOutput 会失败

    我的控制台应用程序遇到了一个棘手的问题 我试图从中重定向 StandardInput StandardOutput 和 StandardError 我已经为其他控制台应用程序找到了一个可行的解决方案 这对我来说并不是什么新鲜事 但这个应用程
  • 有序列表索引

    有什么方法可以获取a的编号 索引 li有序列表中的标签 我正在尝试获取侧面显示的数字 列表编号 我知道传统的方法是使用存储行号的 id 但这意味着如果在中间添加一行 则必须编辑大量 id 尽管我为此开发了一种算法 但它的效率并不高 我正在寻
  • Java中的2d ArrayList添加数据

    我在家庭作业上几乎不需要帮助 我必须创建一个 10 x 10ArrayList 不是数组 这就是我所拥有的 我只需要有关如何执行 for 循环将日期添加到 2D 的提示ArrayList 顺便说一下 这是为了放置成绩数据 从 100 到 8
  • 提取 Javascript 数字的指数和尾数

    有没有一种相当快速的方法可以从 JavaScript 中的数字中提取指数和尾数 AFAIK 没有办法获取 Javascript 中数字后面的位 这让我觉得我正在研究一个因式分解问题 找到m and n这样2 n m k对于给定的k 由于整数
  • || 到底是什么?意思是?

    return empty neededRole strcasecmp role admin 0 strcasecmp role neededRole 0 到底是什么 在这个声明中是什么意思 有人可以帮我把这个翻译成英文吗 我保证我已经用谷歌
  • 32 位应用程序未更新 64 位注册表项

    C 中提到的路径中的注册表项未更新 string path Software Microsoft Windows NT CurrentVersion Windows RegistryKey myKey Microsoft Win32 Reg
  • 绑定不适用于在 XAML 中创建的 DependencyObject

    我尝试使用自定义类在 XAML 中传递多个 CommandParameters 我创建了一个名为值命令参数继承自依赖对象并有两个依赖属性 我们称它们为Value1 and Value2对于这个例子 应该调用命令并传递该对象的按钮如下所示
  • 核心数据在后台保存对象问题

    简而言之 我想要做的是使用后台队列将从 Web 服务提取的 JSON 对象保存到 Core Data Sqlite3 数据库 保存发生在我通过 GCD 创建的序列化后台队列上 并保存到为该后台队列创建的 NSManagedObjectCon
  • Python:包中的“私有”模块

    我有一个包裹mypack带模块mod a and mod b在里面 我想要包裹本身mod a自由进口 import mypack import mypack mod a 不过 我想保留mod b专供mypack 那是因为它的存在只是为了组织
  • 如何在应用程序中使用 iPhone 铃声

    我想在我的应用程序中使用 iPhone 的铃声 这可能吗 请帮助我解决这一点 Thanks 您无法以编程方式使用或更改可用的铃声 很遗憾地说 苹果公司实在是太保守了
  • 添加 TabBarController 作为视图的子视图

    当我的应用程序启动时 我正在加载启动屏幕 然后我想加载一个TabBarController 它是ViewControllers 但是 我的 TabBarController 窗口无法缩放到屏幕尺寸 底部的 TabBar 的 3 4 可能被切
  • 用Windows Forms数据控件和DataTable实现图库式的显示?

    我有一个datatable看起来像下面这样 Room Cook Waiter BG Image 201 Joe Jim Green png 202 Jack Mary Red png 203 Jet Mark Yellow png 204
  • Google 登录 - “access_token”与“id_token”与“代码”

    在我们的网站中 我们过去在使用 Google Sign In 登录人员时使用 access token 首先 我们将用户重定向到 google 用户将 access token 带给我们 我们验证该令牌以确保该用户是实际的 Google 用
  • 无法让 ActiveMQ 重新发送我的消息

    我有一个用 Java 编写的单线程 ActiveMQ 使用者 我想做的就是从队列中接收 一条消息 尝试将其发送到网络服务 如果成功则确认 它 如果 Web 服务调用失败 我希望消息保留在队列中 并在超时后重新发送 除了重新发送部分之外 它或
  • 离开屏幕保护程序或锁定计算机后程序挂起

    我们的程序运行良好 直到有人锁定计算机或弹出屏幕保护程序 但不是 ctrl alt delete 一旦计算机解锁 屏幕保护程序关闭 应用程序就会停止绘制除标题栏之外的所有内容 并停止响应输入 它显示一个大部分为白色的窗口 无法移动或关闭 应