首页 > 解决方案 > 在不同的线程中使用 excel COM 对象

问题描述

我一直在阅读很多东西,我想我理解发生了什么,但我不知道如何解决它。

我有 ac# wpf 应用程序。用户单击一个按钮,我启动另一个线程来做很多工作。其中一部分是打开excel,创建一个excel文件并对excel表做很多事情来设置它。

完成该部分后,用户将使用该应用程序,并且有一些按钮可以进一步与 excel 文件交互,例如添加更多内容。

我的问题是当线程完成时我将该 COM 对象丢失到 excel 文件中。不知道如何解决这个问题。这是我的代码(后期绑定到excel)

..我有一个公共静态类包含在 excel 对象上

public static class MyGlobals
{
    public static string ExcelprogID = "Excel.Application";
    public static dynamic xlWorkBook;
    public static dynamic xlApp;  
}

..然后用户点击一个按钮,我开始另一个线程

private void btnSearch_Click(object sender, RoutedEventArgs e)
{
    string dialogValues = "...";//replaced code for simplicity
    Thread t = new Thread(() => workerthread(dialogValues));
    t.SetApartmentState(ApartmentState.STA);
    t.Start();
}

..然后在新线程中我做了很多,但其中一件事是创建 excel 对象并设置该 excel 表。

private void workerthread(string e)
{
    MyGlobals.xlApp = Activator.CreateInstance(Type.GetTypeFromProgID(MyGlobals.ExcelprogID));
    MyGlobals.xlWorkBook = MyGlobals.xlApp.Workbooks.Add(MyGlobals.misValue);
    MyGlobals.xlApp.Visible = true; 
    //more code here to do stuff with excel.
}

...这是我的问题发生的地方。现在回到主 UI 线程,用户可以单击按钮来操作 excel 文件中的内容。但我得到这个错误

private void btnPlaceBM_Click(object sender, RoutedEventArgs e)
{
    //Excel.Worksheet BM;
    dynamic BM;
    try
    {
        BM = MyGlobals.xlWorkBook.Sheets["CADD Basemaps"];
    }
    catch
    {
        MessageBox.Show("Project Index Excel file was closed! Can not place any data to excel file!");
        return;
    }
}

这是我得到的错误

捕获 System.Runtime.InteropServices.InvalidComObjectException:“无法使用已与其基础 RCW 分离的 COM 对象。”

有人可以给我一些帮助..我能以某种方式重新获取那个 excel 对象吗?

标签: c#multithreadingcom

解决方案


好吧,从评论中我开始思考。我试图在线程结束之前查看如何从工作线程中获取 COM 对象。更改代码太难了,因此 UI 线程在我启动工作线程之前生成 COM 对象,因为直到进入工作线程的中途我才能创建 COM 对象。然后它就撞到了我。当我到达创建 COM 对象的工作线程部分时,我只是将它分派给 UI 线程。现在这可能不是最好的解决方案,但它有效。这是如何在工作线程中执行此操作的代码片段。

private void workerthread(string e)
{
    //code removed for simplicity..

    //Create COM object for excel app & excel workbook in Main thread to prevent object reference loss
    App.Current.Dispatcher.Invoke((Action)delegate
    {
        MyGlobals.xlApp = Activator.CreateInstance(Type.GetTypeFromProgID(MyGlobals.ExcelprogID));
        MyGlobals.xlWorkBook = MyGlobals.xlApp.Workbooks.Add(MyGlobals.misValue);
    });
    MyGlobals.xlApp.Visible = true; 
    //more code here to do stuff with excel.
}

推荐阅读