简体   繁体   English

使用COM对象的后台工作者仍然锁定UI

[英]Background worker using COM object locks UI still

So I don't know how to ask this question and might be one reason I am having issues finding the answers anywhere. 所以我不知道怎么问这个问题,这可能是我在任何地方都找不到答案的原因之一。

So my setup is that I have a class 所以我的设置是我有一堂课

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());
    }
}

In my main class I instantiate a new Connection and call Login which opens a new connection to ALM in TDConnection. 在主类中,我实例化一个新的Connection并调用Login,它在TDConnection中打开一个到ALM的新连接。 In my thread I want to use this already open connection inside of my thread. 在我的线程中,我想在线程内部使用此已打开的连接。 From what I have read, if I do this my UI will block because I am using the methods for the member on the UI thread even though I am inside of the background worker. 根据我的阅读,如果我这样做,我的UI将会阻塞,因为即使我在后台工作人员内部,我仍在使用UI线程中成员的方法。

One solution I have found to do this: 我发现一种解决方案可以做到这一点:

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

        conn.Login();

        conn.ConnectProject();

        e.Result = conn;
    }

I would prefer not to do this because I have already logged in and it takes extra time to do this. 我宁愿不这样做,因为我已经登录,并且这需要花费更多时间。

I have tried passing Connection.TDC in with _bw.RunorkerAsync(Connection.TDC) but this does not work either obviously. 我尝试将_bw.RunorkerAsync(Connection.TDC)与Connection.TDC一起传递,但这显然不起作用。

Is there any way I can use the already established connection and not block the UI while it is connecting? 有什么方法可以使用已经建立的连接,而在连接时不阻止UI?

This is common with COM objects. 这在COM对象中很常见。 Just like .NET classes, many COM coclasses are not thread safe. 就像.NET类一样,许多COM协类也不是线程安全的。 In .NET you get to shoot your own foot if you use a .NET class in a thread-unsafe way. 在.NET中,如果您以不安全线程的方式使用.NET类,则您将无法自拔。 Not in COM, it guarantees that a coclass that advertizes itself as not thread-safe will be used in a thread-safe way. 不在COM中,它保证将以线程安全的方式使用广告自己为非线程安全的coclass。

Which it does by automatically marshaling a method call from a worker thread to the thread that created the object. 它通过自动将方法调用从工作线程编组到创建对象的线程来完成。 You can see where that goes, you created the TDC object on the main thread. 您可以看到结果,您在主线程上创建了TDC对象。 So when you call it from the BackgroundWorker, it will still execute the call on the main thread. 所以,当你从BackgroundWorker的调用它,它仍将执行主线程中调用。

The only way to solve this is to create the object on the same thread that you use it. 解决此问题的唯一方法是在使用对象的同一线程上创建对象。 Which typically also means that you can't use BackgroundWorker, you may well need to create a Thread and call its SetApartmentState() method to switch it to STA. 这通常也意味着您不能使用BackgroundWorker,您很可能需要创建一个Thread并调用其SetApartmentState()方法以将其切换为STA。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM