3

質問:

この質問に対する Mike Rosenblum の回答に対して質問したいです。質問は、Excel 相互運用オブジェクトのクリーンアップに関するものでした。提案されたいくつかの解決策 (たとえば、ラッパー、複数のドットを使用しない、Excel プロセスを強制終了する) が、私はこの問題に対する Mike Rosenblum の解決策が最も気に入りました (このトピックに関する長い記事)。

それが基本的に言っていることは、周りに浮かんでいるすべての参照についてあまり心配しないということです. いくつかの主要なもの(ApplicationClassWorkbookおよび などWorksheet)を保持するだけです。最初にガベージ コレクションを呼び出して、浮遊しているすべてのオブジェクトをクリーンアップし、次にMarshal.FinalReleaseComObject(重要度の逆順で) 呼び出して、まだ残っているメイン参照を明示的にクリーンアップします。

これについて 2 つの質問があります。
最初に: どのオブジェクトへの参照を保持する必要があるかを判断するにはどうすればよいですか? Mike Rosenblum の例ではRanges、 、WorksheetsWorkbooksおよびのみを保持してApplicationClassesいます。
2 番目: オブジェクトが他にもある場合、それらをクリーンアップする順序 (つまり、「重要な順序」) を決定するにはどうすればよいですか?

前もって感謝します。


更新 1:

MattC注文に関して重要なのは、アプリが最後にリリースされることだけであることが示唆されています。ただし、私の参考文献では次の文があります。より多くの順序があることを意味します。

nobugzすべてを に設定してからnullガベージ コレクションを実行するだけで十分であることが示唆されていますが、それは Mike Rosenblum の記事からの次の引用と矛盾しているように思わます。ただし、Microsoft Office アプリケーションは、オブジェクトが解放される順序に敏感であり、残念ながら、変数 =を設定して呼び出しても、オブジェクトの解放順序は保証されません。NothingGC.Collect()NothingGC.Collect()

更新 2:

追加情報: 私自身のアプリケーションでは、チャートを使って多くのことを行います。プロパティなどをいろいろ設定しています。 なるほど、新しいCOMオブジェクトを作るところが多いですね。ダブル ドットを使用しないように注意し、Marshal.FinalReleaseComObject終了したすべてのオブジェクトを呼び出すようにしました。多くのネスティングが発生するため、ラッパー アプローチは使用しませんでした。
EXCEL.exeアプリが作業を終了した後、閉じませんでした。しかし...同じ作業をもう一度行うようにアプリに指示したところ、閉じました。もちろん、EXCEL.exe閉じなかった新しいオープン。今、すべてのMarshal.FinalReleaseComObject呼び出しを削除しましたが、アプリはまったく同じように動作します。EXCEL.exeアプリに作業をやり直すように指示するまで、滞在しますが、その後、新しい開始EXCEL.exeと滞在が続きます。

編集:また、COM以外の他の作業を行うようにアプリに指示すると、しばらくするとEXCEL.exe消えますが、新しいものEXCEL.exeは表示されません。

ここから導き出せる結論はわかりません...

4

3 に答える 3

3

コード内で可能性のあるライブ参照を見つけるのに問題はありません。それらはクラスのフィールドになります。または、クリーンアップ メソッドのローカル変数、それはほとんどありません。リンクで提供されているリストは、フィールドに保存する可能性が最も高いオブジェクトです。他にもあるかもしれませんが、それらは Application オブジェクトと同じように Excel を維持します。

リンクで提唱されているように、削岩機のアプローチをお勧めするとは思いません。それは、デッド COM インターフェイスをラップする RCW への潜在的な生命参照を隠しているだけです。最悪の場合、誤ってオブジェクトを参照したときに例外が発生してプログラムがクラッシュします。Bugz、確かに、簡単に発見できるものではありません. あなたがしなければならないことは、参照を null に設定することだけです。順序は関係ありません。

于 2009-12-01T13:43:21.520 に答える
2

私は同様の問題を抱えていましたが、これは私のキャッチであり、最終的にクリーンアップのように見えます。お役に立てば幸いです。

        .......

        oWB._SaveAs(strCurrentDir +
           strFile, XlFileFormat.xlWorkbookNormal, null, null, false, false,       XlSaveAsAccessMode.xlShared, false, false, null, null);
            sumsheet.Activate();
            oWB.Close(null, null, null);
            oXL.Workbooks.Close();
            oXL.Quit();
        }
        catch (Exception theException)
        {
            theException.ToString();
        }
        #region COM Object Cleanup
        finally
        {
            // Cleanup
            GC.Collect();
            GC.WaitForPendingFinalizers();

            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oRng);
            //System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sumSheet);
            //System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oSheet);
            //oWB.Close(null, null, null);
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oWB);
            oXL.Quit();
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oXL);
        }
        #endregion

編集

sumSheet + oSheet (これは私のワークシートです) は不要だったのでコメントアウトしました。このコードは私にとっては問題なくしっかりしています。エラーが発生した順序を並べ替えて見つけました。

于 2009-12-01T13:21:09.963 に答える
0

アプリケーションが最後である限り、(null でない限り) 任意の順序でリリースできると思います。

次に、GC.Collect を実行して、最終的に Excel.exe プロセスを強制終了します。

于 2009-12-01T13:08:05.963 に答える