現象
Microsoft Visual Basic .NET または Microsoft Visual C# .NET から Microsoft Office アプリケーションを自動化する場合、Quit メソッドを呼び出しても Office アプリケーションは終了しません。
原因
Visual Studio .NET がマネージド コードから COM オブジェクトを呼び出すと、ランタイム呼び出し可能ラッパー (RCW) が自動的に作成されます。 RCW は、.NET アプリケーションと COM オブジェクトの間で呼び出しをマーシャリングします。 RCW は、COM オブジェクトの参照カウントを保持します。 したがって、すべての参照が RCW で解放されていない場合、COM オブジェクトは終了しません。
解決策
Office アプリケーションが終了することを確認するには、オートメーション コードが次の条件を満たしているかどうかを判断します。
各オブジェクトを新しい変数として宣言します。 たとえば、次のコード行を変更します。
oBook = oExcel.Workbooks.Add()これを次のように変更します。
dim oBooks as Excel.Workbooks oBooks = oExcel.Workbooks oBook = oBooks.Add()オブジェクトの使用が完了したときに 0 が返されるまで、ループ内で System.Runtime.InteropServices.Marshal.ReleaseComObject を使用します。 System.Runtime.InteropServices.Marshal.ReleaseComObject は RCW の参照カウントをデクリメントし、ループによって、CLR に再入力された回数に関係なく、基になる COM コンポーネントが確実に解放されます。
変数への参照を解放するには、変数を Nothing または Null に設定します。
Office アプリケーション オブジェクトの Quit メソッドを使用して、サーバーにシャットダウンを指示します。
状態
この動作は仕様です。
追加情報
動作を再現する手順
Visual Studio .NET を起動します。
[ファイル] メニューの [新規] をクリックし、[プロジェクト] をクリックします。 [Visual Basic Projects]\(Visual Basic プロジェクト\) で、[Windows アプリケーション] を選択し、[OK] をクリックします。
メモ Form1 は既定で作成されます。
Microsoft Excel オブジェクト ライブラリへの参照を追加します。 手順は次のとおりです。
[プロジェクト] メニューの [参照の追加] をクリックします。
[COM] タブで、Excel 用オブジェクト ライブラリを見つけて、[選択] をクリックします。
Microsoft Excel 2002 の場合: Microsoft Excel 10.0 オブジェクト ライブラリ
メモ まだこれを行っていない場合は、Microsoft Office XP プライマリ相互運用機能アセンブリ (PIA) をダウンロードしてインストールすることをお勧めします。
Office XP PIA の詳細については、次のマイクロソフト サポート技術情報の記事を参照してください。
328912 Microsoft Office XP プライマリ相互運用機能アセンブリ (PIA) をダウンロードできます
Microsoft Office Excel 2003 の場合: Microsoft Excel 11.0 オブジェクト ライブラリ[参照の追加] ダイアログ ボックスで [OK] をクリックして、選択内容を受け入れます。
[表示] メニューの [ツールボックス] をクリックし、ボタン コントロールを Form1 にドラッグします。
Button1 をダブルクリックします。
メモ フォームのコード ウィンドウが表示されます。
Form1.vbの先頭に次のコードを追加します。
Imports Microsoft.Office.Interopコード ウィンドウで次のコードを置き換えます。
Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click End Sub次のコードに置き換える:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim oApp As New Excel.Application() Dim oBook As Excel.Workbook = oApp.Workbooks.Add Dim oSheet As Excel.Worksheet = oApp.ActiveSheet oSheet = Nothing oBook.Close(False) oBook = Nothing oApp.Quit() oApp = Nothing Debug.WriteLine("Sleeping...") System.Threading.Thread.Sleep(5000) Debug.WriteLine("End Excel") End SubF5 キーを押してアプリケーションを実行します。
Windows タスク マネージャーを開きます。 Visual Studio で、[出力] ウィンドウを表示してデバッグ メッセージを表示します。 コマンド ボタンをクリックします。 Excel.exe のインスタンスが [プロセス] の一覧に表示されます。
Excel のインスタンスは、アプリケーションのスリープが完了した後でも、タスク リストで引き続き実行されます。 ダイアログ ボックスを閉じて、Excel が [プロセス] リストに表示されなくなったことに注意してください。
「解決」セクションの手順を実行すると、Office アプリケーションは最後の変数を解放した後に終了します。 次のコードを使用して、手順 5 の関数を置き換えます。
Private Sub NAR(ByVal o As Object) Try While (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0) End While Catch Finally o = Nothing End Try End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim oApp As New Excel.Application() Dim oBooks As Excel.Workbooks = oApp.Workbooks Dim oBook As Excel.Workbook = oBooks.Add Dim oSheet As Excel.Worksheet = oApp.ActiveSheet NAR(oSheet) oBook.Close(False) NAR(oBook) NAR(oBooks) oApp.Quit() NAR(oApp) Debug.WriteLine("Sleeping...") System.Threading.Thread.Sleep(5000) Debug.WriteLine("End Excel") End Sub
Visual C# .NET を使用している場合は、NAR() 関数のコードを参照してください。
private void NAR(object o)
{
try
{
while (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0) ;
}
catch {}
finally
{
o = null;
}
}
注 .NET Framework 2.0 以降では、System.Runtime.InteropServices.Marshal.FinalReleaseComObject を、System.Runtime.InteropServices.Marshal.ReleaseComObject を呼び出す while ループではなく、System.Runtime.InteropServices.Marshal.ReleaseComObject を使用して同じ結果を実現できます。
トラブルシューティング
メモ 「動作を再現する手順」セクションで説明されている手順に従い、サーバーがまだシャットダウンしない場合は、GC を使用できます。Collect() メソッドと GC。最後のオブジェクトを解放した後の WaitForPendingFinalizers() メソッド。 ランタイムは RCW の GC でガベージ コレクションを実行するためです。Collect() メソッドはガベージ コレクターを強制的に実行し、RCW がまだ持つ参照を解放する可能性があります。 GC。Collect() メソッドは、使用可能な最大メモリの解放を試みます。 これにより、すべてのメモリが解放されるとは限りません。
適用対象
この記事は、次にも適用されます。
- Microsoft Visual Basic .NET (すべてのエディション)
- Microsoft Visual C# .NET (すべてのエディション)
- Microsoft Office 2016 (すべてのエディション)
- Microsoft Office 2013 (すべてのエディション)