タイトル : Re: ループ処理後にExcelのタスクが残る 投稿日 : 2020/03/01(Sun) 17:29 投稿者 : 魔界の仮面弁士
> Public xlBooks As Workbooks > Public xlSheet As Sheets Workbooks の変数名を Books とするのであれば、 Sheets の変数名もまた、Sheet ではなく Sheets とするべきかと。 > xlApp = CreateObject("Excel.Application") それは参照設定しない場合の呼び方ですね。 あながち間違いというわけでも無いのですが、特に理由が無ければ 『xlApp = New Excel.Application()』と記述するが望ましいです。 CreateObject ですとインスタンス生成前に CLSID の逆引きが必要になりますし、 戻り値の型が Object 型になってしまうため「Option Strict On」との相性が悪いためです。 それと xlApp を .Visible = False な状態のまま操作しているようですが、 実行環境によっては、バックグラウンド プロセスの実行優先度が フォアグラウンド プロセスに比べて著しく落ちる可能性があります。 非表示だと遅かった処理が、Visible = True にすることで高速化することも…。 > For i = 0 To (指定回数) 上記がちょっと奇妙に思えました。 回数と称するのであれば、以下のいずれかになるべきかと。 『For i = 1 To (指定回数)』 『For i = 0 To (指定回数) - 1』 『For i = (指定回数) To 1 Step -1』 『For i = (指定回数) - 1 To 0 Step -1』 > Dim xlwkSheet2 As Worksheet = Nothing > Dim xlCells As Range = Nothing > Dim xlRange As Range = Nothing > 'シートのコピー > xlwkSheet2.Copy(After:=xlSheet(i+1)) 上記は明らかに不自然です。 Nothing なオブジェクトに対して Copy メソッドを呼び出そうとすれば、 NullReferenceException の例外になってしまうはずですよね。 もしかして「xlwkSheet.Copy(After:=xlSheet(i+1))」の間違い? それとも例外を握りつぶしている箇所があるのでしょうか? (Try 句と Err オブジェクトが共存している点も気にかかるところ) あるいは実際のコードでは、変数 xlwkSheet2 に対して、 あらかじめ有効なインスタンスがセットしてあるのでしょうか? もしも、xlwkSheet2 のインスタンスがセット済みだとしても、渡すべき引数が > xlwkSheet2.Copy(After:=xlSheet(i+1)) になっていては、引数に渡した COM オブジェクトを解放できなくなるという問題があります。 引数に渡す COM オブジェクトも変数に受け、解放するようにしてください。 正しい Copy 手順については、次の投稿にて後述します。 また、xlwkSheet2 にインスタンス変数がセットされていたのだとすれば、 その変数が参照していた直前のインスタンスを解放することなく、 > xlwkSheet2 = DirectCast(xlSheet("Sheet1 (2)"),Worksheet) のように、別のインスタンスへの参照に上書きしてしまうのも、あまりに乱暴です。 参照先を書き換える場合は、事前に参照していたインスタンスの解放も忘れずに。 > xlwkSheet2.Name = "A" + i 上記は「コンパイルエラー」になってしまい、実行すらできないはず…。 どのバージョンの VB をお使いでしょうか? もしもコンパイル時のオプション設定が Option Strict Off Option Infer Off Option Explicit Off になっていれば、コンパイルだけは一応通るのですが、それでも実行すれば InvalidCastException の例外を引き起こしてしまうと思います。 > System.Runtime.InteropServices.Marshal.ReleaseComObject(xlwkSheet) > System.Runtime.InteropServices.Marshal.ReleaseComObject(xlwkSheet) そもそも、ループ中で一回も xlwkSheet が登場していないのですが…? それと、参照カウントが 0 になるまで解放することを目的とするのであれば、 ReleaseComObject を複数回呼び出すかわりに、 FinalReleaseComObject を呼ぶ方が、コードの意図が分かり易くなりますよ。 (まぁ、参照カウントが増えすぎてしまうこと自体、そもそも望ましくないのですけれども) > @Copyメソッドの使用後にComのカウントが2になっています。 > Aループの回数を1にしたときは適切にExcelのプロセスが終了されますが、 提示頂いたコードが不完全なので確証は持てませんが、根本的には Sheet 型のインスタンスを保持・解放し忘れているのが原因だと思います。 特に、xlSheet(i+1) の戻り値は、As Object であることも要因の一つです。 また、「COM オブジェクトを引数に取るメソッド」に対して、 明示的な型ではなく、汎用の Object 型を通じて引数を渡した場合、 内部的な型判定の際に参照カウントが増加しやすくなるという傾向があります。 引数として COM オブジェクトを引き渡す必要がある場合は、 「そのインスタンスを変数に保持しておく」 「Object 型ではなく、正しい型で渡すようにする」 「引数に渡し終わった後は、きちんと解放する」の 3 つを守りましょう。 |