DOBON.NETプログラミング道掲示板

No35244 の記事


■35244 / )  Re[1]: Excel Com オブジェクトの増殖
□投稿者/ 魔界の仮面弁士 大御所(1486回)-(2022/11/27(Sun) 08:37:41)
  • アイコンNo35241に返信(たこさんの記事)
    > Excelの処理部分はクラスにまとめ処理していますが、タスクマネージャーで見ると閉じたはずのExcelが残っています。
    > いろいろやってみましたが解決できず、お知恵をお借りしたいと投稿致します。
    省略されている箇所に問題があるような気もしますね。

    たとえば、使用例のところで
    >     ExEx1 = New ExcelEx()
    >     ExEx1.WorkBook = path & "Test.xlsx"
    >     ExEx1.xlsApplication.WindowState = Excel.XlWindowState.xlMaximized
    >     ExEx1.Sheets(1)
    >     ExEx1.WorkBook = "Close"
    と書かれていますが、Sheets メソッドの実装が不明瞭ですし。



    > Friend xlsApplication As Excel.Application = Nothing
    これらの COM オブジェクトを非 Private として公開されていますが、
    Friend で公開するにしても、ReadOnly な Property にしておくべきかと。

    ただし ReadOnly だとしても、ExcelEx 外から Open や Close 等、あるいは Cells 等への
    アクセスは無制限に可能となってしまいますので、COM オブジェクトを直接公開すると、
    ExcelEx だけでは、参照と解放の管理をまかないきれなくなることがあります。


    解放まですべてクラス側で管理するなら、委譲している Excel のオブジェクトを
    直接公開するのではなく、必要な操作のみを再公開するようにしたうえで、
    IDisposable パターンも追加実装しておくのが安全です。実装量は爆発的に増えますけれどね。
    https://learn.microsoft.com/ja-jp/dotnet/standard/garbage-collection/implementing-dispose
    https://ufcpp.net/study/csharp/rm_disposable.html

    逆に、そこまでの実装コストをかけられないというのであれば、
    ヘルパーライブラリとしての実装に留めるという手もあろうかと。


    > Private _WorkBookIsNew As Boolean = Nothing
    = False と書いた方が素直ではありませんか?


    > Public Property WorkBook As String
    今回の COM 解放の問題からは外れますが、こういったものはプロパティではなく、
    String 引数を持ったメソッドとして実装する方が望ましいです。

    クラス設計的には、プロパティは "状態" を表すものであり、
    "動作" を行うことを目的としたプロパティを実装すべきではありません。
    "動作" を目的とするのはメソッドの役目ですよね。

    16bit 時代の Visual Basic ではプロパティで動作させていたりもしますがね…。
    (例:32bit 版では非推奨になった CommonDialog.Action プロパティなど)


    > Private Sub WorkBook_Open(Optional ByVal strFileName As String = Nothing)
    >     'Excel アプリケーション起動
    >     xlsApplication = New Excel.Application
    WorkBook_Open が 2 回呼ばれると、xlsApplication 変数が
    以前に編集していたインスタンスを破棄することなく、
    新しい Application インスタンスを生成することになりそうですが、
    何らかの再入防止策が組み込まれていますか?

    インスタンス管理を考えると、Application の起動は
    ExcelEx のコンストラクタで行った方が良いと思います。


    >     MRComObject(xlsRange, True)
    ExcelEx の他の部分の処理がどうなっているのかにもよりますが、
    Range オブジェクトは複数使われることも多いので、
    自分ならコレクション管理するかな…?

    >     If Not xlsWorkbook Is Nothing Then xlsWorkbook.Close()
    省略された部分のコードによって、この時点で Nothing になっていることがあるということですか?

    提示された範囲のコードを見るだけでは、ここで Nothing になっているケースとは、外部から
     ExEx1.xlsWorkbook = Nothing
    とされた場合か、あるいは WorkBook_Open がまだ呼ばれていない時ぐらいしかなさそうですが…。
    (または、存在しないファイル名を指定するなどして、WorkBook_Open が失敗した場合とか)

    あと、xlsWorkbook.Saved が False の時に Close を呼び出すと、
    DisplayAlerts が True に戻されていた場合、保存確認のダイアログが表示されることになります。
    そして保存確認でキャンセルされた場合、実際には Close されません。

    もしも終了時の保存が常に不要な場合は、Close 前に Saved プロパティを True にしておくか、
    もしくは Close メソッドの SaveChanges 引数に False を指定するようにします。


    > Excelを閉じた時にプロセスは終了・削除されると思っているのですが、認識が違うのでしょうか…
    .NET 側を解放したとしても、ReleaseComObject されねば COM 側は生き残りますが、
    その逆に COM 参照が残っている状態で Excel を閉じた場合、終了せずに非表示だけで留まることがあります。

    逆に、 COM 側だけが解放されたとしたら、解放済みのオブジェクトを操作するタイミングで、
    HRESULT: 0x80010108 (RPC_E_DISCONNECTED) に相当する例外
    たとえば「起動されたオブジェクトはクライアントから切断されました。」などが
    発生する可能性があります。
違反を報告
返信 削除キー/


Mode/  Pass/


- Child Tree -