2016-08-20 6 views
2

Officeオートメーションを使用してExcelファイルを作成するDelphi XE8プログラムがあります。ビルドには数秒かかりますので、私はこのプログラムをバックグラウンドスレッドに入れて、プログラムが応答性を保ち、キャンセル要求を処理できるようにしました。Windows 7およびOffice 2007でOfficeオートメーションがハングする

私はこの方法でそれを設定していた:

TTask.Run(
    procedure 
    var 
    oXL, oSheet, o2Sheet, oRng, VArray : Variant; 
    begin 
    oXL := CreateOleObject('Excel.Application'); 
    oXL.Visible := False; 
    oXL.DisplayAlerts := false; 

    ... (all the processing to build the Excel file) 

    oXL.Application.Workbooks[1].SaveAs(ExcelFilename, 51 { = xlWorkbookDefault }); 
    oXL.Workbooks.Close; 
    oXL.Application.Quit; 
    oXL := Unassigned; 
    end 
); 

このコードは絶対にうまく働いた、私はそれが欲しかっただけの方法を。 Excelワークブックをバックグラウンドタスクとして作成し、完了したらタスクからメインスレッドに戻し、アプリケーションは応答性のままでした。

私はすべてが素晴らしかったと思いました。それはOffice 2016を搭載した私のWindows 10コンピュータで働いていました。

しかし、スレッド中にプログラムがハングアップしているという1人のユーザーからの報告がありました。私はいくつかのテストをすることができました。コードが自分のマシン上のスレッドで実行されていないとき、アプリケーションは正常に動作しなくなり、キャンセル要求を処理できなくなりました。私が言うことができるユーザのマシンについて異なる

唯一のことは、彼らは、Windows 7とOffice 2007に

を実行していた私は、オフィスオートメーションスレッドセーフであることを100%確かではないよということです。いくつかの自動化コマンド(どちらのコマンド)を同期させる必要があるかもしれないと理解して、スレッドにすべてを入れることはできますか?スレッドセーフでない場合は、Excelファイルが生成されている間にアプリケーションを応答可能にする方法はありますか?

Windows 7のOffice AutomationとWindows 10またはOffice 2007の違いとOffice 2016の違いにより、タスクが以前のバージョンで失敗する可能性がありますか。もしそうなら、回避策はありますか?

+0

確かに、実際のコードでは51とは言えません。マジック定数を使用するのをやめ、適切な定数を定義する必要があります。 –

+0

@DavidHefferman - オフィスオートメーション定数がDelphi XE8 Proパッケージに含まれていないため、使用するコード(xlWorkbookDefault)とその値が何であるかを見つけるためにウェブを検索しなければなりませんでした。 – lkessler

+0

コード内に定義します。 –

答えて

5

明白な欠陥は、スレッドでCOMを初期化しなかったことです。 CoInitializeまたはCoInitializeExに電話してください。

Excelをバックグラウンドスレッドから自動化することはもちろん問題ありません。あなたが試みていることは可能です。表示されていないコードにバグがあると考えられますが、COM初期化が欠落しているのは、その質問のコードで確認できる唯一の障害です。

もちろん、スレッドの寿命を制御しないとCOMの初期化は容易ではありません。スレッドライブラリはスレッドを作成し、そのスレッドで何が実行されているのかは分かりません。私があなただったら、スレッドを明示的に作成し、スレッドベースのライブラリのタスクベースのアプローチを回避します。

+0

スレッドはExcelファイルのビルディングのみを実行しています。 CreateOleObjectステートメントとClose/Quitステートメントだけを入れ、他のすべてを残しておくのは同じ結果になるため、私のコードのバグが原因ではありません。私の質問で注意しなかった重要なことは何か(またはそうでないかもしれない)です。私がCreateOleObjectとClose/QuitオブジェクトをSynchronizeステートメントに入れると、それは自分のマシン上で動作します。もちろん、それは単にメインスレッドで再び実行されます。 – lkessler

+0

あなたのコードには必ずバグがあります。何よりも自分のコードを常に疑う。表示されている大きなバグは、私が言ったように、COMを初期化していないことです。 VCLアプリケーションでは、COMはメインスレッドで初期化されます。 –

+0

技術的にはバグではなく*私のコードです。私のコードから何かを残したので、バグです。 :-) – lkessler

関連する問題