gpt4 book ai didi

c# - SystemEvents.SessionSwitch导致我的Windows窗体应用程序卡住

转载 作者:行者123 更新时间:2023-12-03 13:15:16 45 4
gpt4 key购买 nike

我在.NET 4.5上有一个C#Windows窗体应用程序。

该应用程序连接到USB设备。

我想同时支持多个 session 。

为此,我需要在 session 锁定时从该设备断开连接,以允许新 session 连接到该设备。

我使用SystemEvents.SessionSwitchEventArgs.Reason来检测此类事件:
- session 切换上的SessionSwitchReason.ConsoleDisconnect
-SessionSwitchReason.ConsoleConnect在 session 切换后解锁

此事件似乎是完美的解决方案,但有时在随机时间(经过多次锁定或解锁后),该事件不会触发并且UI冻结。
值得注意的是,当应用程序在调试器中运行时,不会发生这种情况。

我从日志中知道其他一些后台线程仍在正常工作,但UI冻结,并且未调用该事件的预订函数。

我的代码示例:

Program.cs:

using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MyProgram
{
static class Program
{
private static Mutex mutex = null;
[STAThread]
static void Main()
{
const string appName = "MyProgram";
bool createdNew;

mutex = new Mutex(true, appName, out createdNew);

if (!createdNew)
{
//app is already running! Exiting the application
return;
}

Application.EnableVisualStyles();

//This was one attempt to solve the UI deadlock Microsoft.Win32.SystemEvents.UserPreferenceChanged += delegate { };

Application.SetCompatibleTextRenderingDefault(false);
MyProgramEngine MyProgramEngine = new MyProgram.MyProgramEngine();
Application.Run(MyProgramEngine.getForm());
}
}

}

MyProgramEngine:
using log4net;
using log4net.Config;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using WindowsInput;
using System.Windows.Forms;
using Microsoft.Win32;


namespace MyProgram
{
class MyProgramEngine
{
private MainForm mainForm;
public MyProgramEngine()
{
XmlConfigurator.Configure();
Utility.logger.Info(string.Format("MyProgram Started. Version: {0}", Application.ProductVersion));
SystemEvents.SessionSwitch += new SessionSwitchEventHandler(SystemEvents_SessionSwitch);
if (!GlobalSettings.getInstance().isProperlyConfigured())
{
WarningForm warningForm = new WarningForm("MyProgram is not properly configured. Please contact support");
warningForm.ShowDialog();
Application.Exit();
Environment.Exit(0);
}
mainForm = new MainForm();
initArandomBackgroundThread();
initDeviceThread();
}

private void initDeviceThread()
{
Thread detectAndStartReader = new Thread(initDevice);
detectAndStartReader.IsBackground = true;
detectAndStartReader.Start();
}

public void initDevice()
{
//Connect to device
//Start device thread
}

public MainForm getForm()
{
return mainForm;
}


//Handles session switching events
internal void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
try
{
if (e.Reason.Equals(SessionSwitchReason.ConsoleDisconnect))
{
DisconnectFromDevice();
TerminateDeviceThread();
}
else if (e.Reason.Equals(SessionSwitchReason.ConsoleConnect))
{
initDeviceThread();
}
else
{
Utility.logger.Info("The following SesseionSwitchReason has been caught: " + e.Reason + " , No action!");
}
}
catch (Exception ex)
{
Utility.logger.Error("Something bad happened while managing session switching events", ex);
}

}

}

注意:我对SessionSwitchReason.SessionUnlock或SessionSwitchReason.SessionLock不感兴趣,因为我都不希望对 session 锁定执行任何操作,也不想在同一 session 上解锁。

感谢您的支持!

最佳答案

我发现了错误所在。
简单来说,
永远不要在后台工作线程上创建控件。
在我的代码中,如果删除了SessionSwitch事件订阅,则仍然会发生挂起。我能够将主线程上的等待追溯到SystemSettingsChanging,它也是一个SystemEvent,但我不控制。
在我几乎放弃尝试解决此问题后,我逐行阅读了代码,这使我发现正在后台线程上创建一个Form(弹出窗口)。
如上面给出的示例所示,这部分代码没有引起我的注意。

initArandomBackgroundThread();


要了解有关此冻结的更多信息,可以前往 Microsoft Support进行详细说明。
Microsoft声称这种冻结的底层原因

This occurs if a control is created on a thread which doesn't pump messages and the UI thread receives a WM_SETTINGCHANGE message.

Common causes are a splash screens created on a secondary UI thread or any controls created on worker threads.


修复

Applications should never leave Control objects on threads without an active message pump. If Controls cannot be created on the main UI thread, they should be created on a dedicated secondary UI thread and Disposed as soon as they are no longer needed.


调试

One way to identify which windows are created on which thread is with Spy++ in the Processes view (Spy.Processes menu). Select the hung process and expand its threads to see if there are any unexpected windows. This will find the native window if it still exists; however, the problem can occur even if the native window has been destroyed, so long as the managed Control has not yet been Disposed.

关于c# - SystemEvents.SessionSwitch导致我的Windows窗体应用程序卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45707940/

45 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com