1

この機能を持つExcelアドインクラスがあります:

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";
}

リボンにボタンを追加しました。このボタンを押すと、スレッドで testRibbon が呼び出されます。

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

これにより、キャスト エラーが発生します。

タイプ 'System.__ComObject' の COM オブジェクトをインターフェイス タイプ 'Microsoft.Office.Interop.Excel._Workbook' にキャストできません。IID '{000208DA-0000-0000-C000-000000000046}' を持つインターフェイスの COM コンポーネントでの QueryInterface 呼び出しが次のエラーにより失敗したため、この操作は失敗しました: タイプ ライブラリ/DLL の読み込み中にエラーが発生しました。(HRESULT からの例外: 0x80029C4A (TYPE_E_CANTLOADLIBRARY))。

新しいスレッドを使用しないと、キャスト エラーは発生しません。

編集:タスクファクトリを使用してみましたが、同じエラー:

var task2 = Task.Factory.StartNew(
() =>
{
     Globals.BobStats.testRibbon();
});
4

3 に答える 3

2

ExcelのCOMインターフェイスは基本的にシングルスレッドであるため、Excelで複数のスレッドを使用しても意味がありません(この記事を参照)。アドイン内からさらに制限がある場合があります。

それでも、エラーメッセージが何を言おうとしているのか本当に理解していないと言わざるを得ません。

于 2012-08-10T20:47:56.350 に答える
1

ワーカー スレッドから Excel インターフェイス メソッドを使用する場合、メソッド呼び出しをマーシャリングする必要があります。つまり、Application オブジェクトを作成したスレッドから呼び出しを行う必要があります。.NET GUI アプリで Control.Invoke() または Dispatcher.Invoke() を使用するのと同じ考え方です。

これを機能させるには、COM はメソッドの引数が何であるかを認識して、それらを適切にコピーできるようにする必要があります。これは、.NET の Reflection に相当するものを必要とする種類の情報です。これにはメタデータが必要です。COM メソッドを記述するメタデータは、タイプ ライブラリに格納されます。Excel のタイプ ライブラリは、リソースとして Excel.exe に格納されます。

ここで間違っているのは、タイプ ライブラリを見つけることです。この情報はレジストリに保存され、何らかの理由でマシン上で破損しています。打たれた可能性が最も高いキーはHKLM\SOFTWARE\Classes\TypeLib\{00020813-0000-0000-C000-000000000046}\1.7\0\win32、Office の正確なバージョンに依存しますが. SysInternals の ProcMon ユーティリティからより多くの洞察を得ることができます。プログラムがキーを検索していることがわかります。

この種の事故が 1 つのキーだけに限定されることはめったにありません。マシンを正常な状態に戻し、Office を再インストールする必要があります。

ああ、コードは実際にはワーカー スレッドで実行されないことに注意してください。これには、そのワーカー スレッドで Application オブジェクトを作成し、開始する前に SetApartmentState() を呼び出して STA にする必要があります。

于 2012-08-10T21:42:36.690 に答える
1

現時点では、COMObject によってインターフェイス タイプ 'Workbook' に接続されていると思います...新しいアンマネージ スレッドが自動的に作成され、Start() を実行するとスレッドでクラッシュします。具体的には、スレッドオブジェクトを作成すると、一部のデータ構造が共有メモリに保存され、Start() を使用しなかったため、現時点ではスレッドが実行されていませんでした

于 2012-08-10T20:30:25.777 に答える