この記事が適用されるその他の製品を参照してください。

現象

Microsoft Visual Basic Microsoft Office .NET または Microsoft Visual C# .NET から Microsoft Office アプリケーションを自動化すると、Quit メソッドを呼び出しても Office アプリケーションは終了します。

原因

.NET Visual Studioコードから 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 に設定します。

  • アプリケーション オブジェクトの Quit Officeを使用して、サーバーにシャットダウンを指定します。

状態

この動作は仕様です。

詳細情報

動作を再現する手順

  1. .NET Visual Studio開始します。

  2. [ファイル] メニューの [新規] をクリックし、[ファイルのProject。 [Visual Basic] で 、[アプリケーションのWindows] を選択し、[OK] をクリックします。

    Form1 は既定で作成されます。

  3. オブジェクト ライブラリに参照Microsoft Excel追加します。 この場合、次の手順を実行します。

    1. [プロジェクト] メニューの [参照の追加] をクリックします。

    2. [COM] タブで[オブジェクト ライブラリ] を探しExcel選択] をクリックします。

      Microsoft Excel 2002: Microsoft Excel 10.0 Object LibraryNote

      まだ実行していない場合は、Microsoft Office XP プライマリ相互運用アセンブリ (PIA) をダウンロードしてインストールすることをお勧めします。

      XP PIA のOffice詳細については、次の Microsoft サポート技術情報の記事を参照してください。

      328912 Microsoft Office XP プライマリ相互運用アセンブリ (PIA) をダウンロードできます。
        2003 Microsoft Office Excel: Microsoft Excel 11.0 オブジェクト ライブラリ

    3. [参照の追加] ダイアログ ボックスで [OK] をクリックして、選択内容を承諾します。

  4. [表示] メニューの [ツールボックス] をクリックし、[ボタン] コントロールを Form1 にドラッグします。

  5. Button1 をダブルクリックします。

    フォームのコード ウィンドウが表示されます。

  6. Form1.vb の上部に次のコードを追加します。

    Imports Microsoft.Office.Interop
    
  7. コード ウィンドウで次のコードを置き換えます。

        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 Sub
    
  8. F5 キーを押してアプリケーションを実行します。

  9. タスク Windowsを開きます。 [Visual Studio出力] ウィンドウを表示して、デバッグ メッセージを表示します。 コマンド ボタンをクリックします。 [プロセス] の一覧にExcel.exeインスタンスが表示されます。

  10. アプリケーションのスリープExcel後も、タスク リストでインスタンスが引き続き実行されます。 ダイアログ ボックスを閉じて、[プロセス] Excelが表示されなくなったのを確認します。

  11. 「解決」セクションの手順を実行すると、最後の変数を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
    

.NET のコードVisual C#、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 を呼び出し、同じ結果を得られます。
 

トラブルシューティング

 「動作を再現する手順」セクションで説明されている手順に従って、サーバーがまだシャットダウンされない場合は、GC を使用できます。Collect() メソッドと GC。最後のオブジェクトを解放した後の WaitForPendingFinalizers() メソッド。 ランタイムは RCW (GC) でガベージ コレクションを実行します。Collect() メソッドはガベージ コレクターを強制的に実行し、RCW がまだ持っている参照を解放する可能性があります。 GC。Collect() メソッドは、使用可能な最大メモリを回収します。 これは、すべてのメモリが解放される保証にはならないので注意してください。

適用対象

この記事は、次の場合にも適用されます。

  • Microsoft Visual Basic .NET (すべてのエディション)

  • Microsoft Visual C# .NET (すべてのエディション)

  • Microsoft Office 2016 (すべてのエディション)

  • Microsoft Office 2013 (すべてのエディション)

ヘルプを表示

スキルを磨く
トレーニングの探索
新機能を最初に入手
Microsoft Insider に参加する

この情報は役に立ちましたか?

言語の品質にどの程度満足していますか?
どのような要因がお客様の操作性に影響しましたか?

ご意見をいただきありがとうございます。

×