Skip to main content
 首页 » 编程设计

c#之使用 COM 对象的后台 worker 仍然锁定 UI

2024年02月02日35lovecherry

所以我不知道如何提出这个问题,这可能是我无法在任何地方找到答案的原因之一。

所以我的设置是我有一个类

public class Connection 
{ 
    public static event EventHandler LogggedIn; 
    public static TDConnection TDC {get;set;} 
    public string Authenticate(){...} 
    public static void Login() 
    { 
        if (Connection.TDC.Connected) 
        { 
            _bw = new BackgroundWorker 
            { 
                WorkerReportsProgress = true, 
                WorkerSupportsCancellation = true 
            }; 
            _bw.DoWork += ConnectToProject_DoWork; 
            _bw.RunWorkerCompleted += ConnectToProject_RunWorkerCompleted; 
 
            _bw.RunWorkerAsync(Connection.TDC); 
        } 
    } 
 
    private static void ConnectToProject_DoWork(object o, DoWorkEventArgs e) 
    { 
        Connection.TDC.ConnectProjectEx(Connection.Domain, Connection.Project, Connection.UserName, Utilities.Encryption.AESEncryption.Decrypt(Connection.Password, "fsd*#(dfs(((>>>???fdjs")); 
    } 
 
    private static void ConnectToProject_RunWorkerCompleted(object o, RunWorkerCompletedEventArgs e) 
    { 
        LogggedIn(null, new EventArgs()); 
    } 
} 

在我的主类中,我实例化了一个新的连接并调用登录,它在 TDConnection 中打开一个到 ALM 的新连接。在我的线程中,我想在我的线程中使用这个已经打开的连接。据我所知,如果我这样做,我的 UI 将被阻塞,因为即使我在后台工作程序中,我也在 UI 线程上使用成员的方法。

我找到了一个解决方案:

private static void ConnectToProject_DoWork(object o, DoWorkEventArgs e) 
    { 
        TDConnection conn = new TDConnection(); 
        conn.InitConnectionEx(QCURL); 
 
        conn.Login(); 
 
        conn.ConnectProject(); 
 
        e.Result = conn; 
    } 

我宁愿不这样做,因为我已经登录并且这样做需要额外的时间。

我已经尝试通过 _bw.RunorkerAsync(Connection.TDC) 传递 Connection.TDC,但这显然也不起作用。

有什么方法可以使用已经建立的连接并且在连接时不阻塞 UI?

请您参考如下方法:

这在 COM 对象中很常见。就像 .NET 类一样,许多 COM 组件类不是线程安全的。在 .NET 中,如果您以线程不安全的方式使用 .NET 类,您就会搬起石头砸自己的脚。不是在 COM 中,它保证声明自己不是线程安全的 coclass 将以线程安全的方式使用。

它通过自动将工作线程的方法调用编码到创建对象的线程来实现。您可以看到发生了什么,您在主线程上创建了 TDC 对象。因此,当您从 BackgroundWorker 调用它时,它仍会在主线程上执行调用。

解决这个问题的唯一方法是在您使用它的同一个线程上创建对象。这通常也意味着您不能使用 BackgroundWorker,您可能需要创建一个 Thread 并调用其 SetApartmentState() 方法以将其切换到 STA。