CastError when calling interop Excel functions in a thread?

1

I have an excel addin class that has this function:

public void testRibbon()
{
     Excel.Workbook workbook = this.Application.ActiveWorkbook;      
     Excel.Worksheet activeSheet = workbook.Sheets[1];
     Excel.Range range = activeSheet.get_Range(JOB_ID_FIELD + HEADER_ROW, TOTAL_STATUS_PERCENTAGE_KEY_FIELD + (10 + 1).ToString());
     range.get_Range("C4").Value = "test Ribbon complete";
}

In the ribbon I added a button that when pressed will call testRibbon in a thread:

private void process_Click(object sender, RibbonControlEventArgs e)
{
    Thread processThread = new Thread(delegate(){
        Globals.ExcelAddin.testRibbon();
    });
    processThread.Start();
} 

This causes a cast error:

Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.Office.Interop.Excel._Workbook'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{000208DA-0000-0000-C000-000000000046}' failed due to the following error: Error loading type library/DLL. (Exception from HRESULT: 0x80029C4A (TYPE_E_CANTLOADLIBRARY)).

The cast error doesn't happen if I don't use a new thread.

Edit:Tried using task factory, same error:

var task2 = Task.Factory.StartNew(
() =>
{
     Globals.BobStats.testRibbon();
});
c#
excel
excel-interop
asked on Stack Overflow Aug 10, 2012 by Razor Storm • edited Aug 10, 2012 by Razor Storm

3 Answers

2

Using multiple threads in Excel makes no sense because Excel's COM interface is basically single threaded (see this article). There might be further restrictions from within an add-in.

Yet I have to say I don't really understand what the error message is trying to say.

answered on Stack Overflow Aug 10, 2012 by Codo
1

I think at the moment, you are being connected by COMObject to interface type 'Workbook'... it will automatically create a new unmanaged thread and that will crash with your thread when you Start(). To specifically, when you create thread object it will save some data structures to shared memory and did not use Start() so thread was not executing at this time

answered on Stack Overflow Aug 10, 2012 by cat_minhv0
1

When you use an Excel interface method from a worker thread then the method call needs to be marshaled. In other words, the call needs to be made from the thread that created the Application object. Same idea as using Control.Invoke() or Dispatcher.Invoke() in a .NET gui app.

To make that work, COM needs to know what the arguments are for the method so it can copy them properly. That is the kind of info that requires the equivalent of Reflection in .NET. Which requires metadata, the metadata that describes a COM method is stored in a type library. The type library for Excel is stored in Excel.exe as a resource.

Finding the type library is what is going wrong here. This info is stored in the registry and it is damaged on your machine for some reason. The most likely key that got whacked is HKLM\SOFTWARE\Classes\TypeLib\{00020813-0000-0000-C000-000000000046}\1.7\0\win32 albeit that it depends on the exact version of Office. You can get more insight from SysInternals' ProcMon utility, you'll see your program searching for the key.

This kind of mishap is rarely limited to just one key. You'll need to get your machine healthy again and reinstall Office.

Oh, and keep in mind that the code doesn't actually run on the worker thread. That requires creating the Application object on that worker thread and calling SetApartmentState() to make it STA before you start it.

answered on Stack Overflow Aug 10, 2012 by Hans Passant

User contributions licensed under CC BY-SA 3.0